summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
authorHolger Schurig <schurig@mn-solutions.de>2004-09-30 14:49:57 +0000
committerHolger Schurig <schurig@mn-solutions.de>2004-09-30 14:49:57 +0000
commit51a1649782b24ee9a6ec1e20a83b02f5e3b8f4dd (patch)
tree6654c56857a68f1ab6a70824e6996ebe19d6d4fa /linux
parent7d5b527f225ceb3c28a1942a065da143ea87f593 (diff)
some MNCI "Ramses" related changes
BKrev: 415c1d15quLlMWHqQc8WEmYm8QzznA
Diffstat (limited to 'linux')
-rw-r--r--linux/mnci-ramses-2.4.21-rmk2-pxa1/mnci-combined.patch19914
-rw-r--r--linux/mnci-ramses_2.4.21-rmk2-pxa1.oe14
2 files changed, 19927 insertions, 1 deletions
diff --git a/linux/mnci-ramses-2.4.21-rmk2-pxa1/mnci-combined.patch b/linux/mnci-ramses-2.4.21-rmk2-pxa1/mnci-combined.patch
index e69de29bb2..55d91b9a36 100644
--- a/linux/mnci-ramses-2.4.21-rmk2-pxa1/mnci-combined.patch
+++ b/linux/mnci-ramses-2.4.21-rmk2-pxa1/mnci-combined.patch
@@ -0,0 +1,19914 @@
+
+# This is a cumulative patch consisting of:
+#
+# linux-vtcomparison.patch
+# linux-mkdep.patch
+# linux-iw241_we16-6.patch
+# arm-noshortloads.patch
+# pxa-pcmcia.patch
+# pxa-smc91x.patch
+# pxa-usb.patch
+# pxa-usbeth.patch
+# pxa-irda.patch
+# pxa-ac97.patch
+# pxa-timerint.patch
+# fb-buffered.patch
+# fb-turn180.patch
+# i2c-ds1337.patch
+# keyb-input.patch
+# keyb-module.patch
+# logo-noscrollregion.patch
+# net-dhcp-timeout.patch
+# pm.patch
+# swap-performance.patch
+# small-nocramdisk.patch
+# smc91x-ethtool.patch
+# ucb1x00.patch
+# vmalloc.patch
+# usb-sl811.patch
+# orinoco013e.patch
+# ramses.patch
+# ramses-ac97.patch
+# ramses-keyb.patch
+# ramses-mtd.patch
+# ramses-orinoco-ignorecis.patch
+# ramses-pcmcia.patch
+# ramses-serial.patch
+# ramses-smc91x.patch
+# ramses-sysctl.patch
+# ramses-ucb1x00-dejitter.patch
+# ramses-lcd.patch
+# ramses-usb.patch
+# ramses-corevolt.patch
+# wedge.patch
+# usb-sonycamera.patch
+# ramses-ucb1x00-rotate.patch
+# vt-noblank.patch
+#
+# Patch managed by http://www.holgerschurig.de/patcher.html
+#
+
+--- linux-2.4.21/Makefile~linux-mkdep
++++ linux-2.4.21/Makefile
+@@ -14,10 +14,11 @@
+ else echo sh; fi ; fi)
+ TOPDIR := $(shell /bin/pwd)
+
++PATH := /usr/local/arm/3.3/bin:$(PATH)
+ HPATH = $(TOPDIR)/include
+ FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net $(HPATH)/math-emu
+
+-HOSTCC = gcc
++HOSTCC = ccache gcc
+ HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+
+ CROSS_COMPILE = arm-linux-
+@@ -28,7 +29,7 @@
+
+ AS = $(CROSS_COMPILE)as
+ LD = $(CROSS_COMPILE)ld
+-CC = $(CROSS_COMPILE)gcc
++CC = ccache $(CROSS_COMPILE)gcc
+ CPP = $(CC) -E
+ AR = $(CROSS_COMPILE)ar
+ NM = $(CROSS_COMPILE)nm
+@@ -80,6 +81,7 @@
+ # makefile but the arguement can be passed to make if needed.
+ #
+
++export INSTALL_MOD_PATH = /tftpboot/ramses2
+ MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
+ export MODLIB
+
+@@ -140,7 +142,6 @@
+ DRIVERS-y += drivers/serial/serial.o \
+ drivers/char/char.o \
+ drivers/block/block.o \
+- drivers/misc/misc.o \
+ drivers/net/net.o
+ DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o
+ DRIVERS-$(CONFIG_DRM_NEW) += drivers/char/drm/drm.o
+@@ -197,6 +198,7 @@
+ DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o
+ DRIVERS-$(CONFIG_PLD) += drivers/pld/pld.o
+ DRIVERS-$(CONFIG_ARCH_AT91RM9200) += drivers/at91/at91drv.o
++DRIVERS-y += drivers/misc/misc.o
+
+ DRIVERS := $(DRIVERS-y)
+
+@@ -416,7 +418,7 @@
+ endif
+ .PHONY: _modinst_post
+ _modinst_post: _modinst_post_pcmcia
+- if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
++# if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
+
+ # Backwards compatibilty symlinks for people still using old versions
+ # of pcmcia-cs with hard coded pathnames on insmod. Remove
+@@ -495,7 +497,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
+@@ -574,3 +576,14 @@
+ . scripts/mkversion > .version ; \
+ rpm -ta $(TOPDIR)/../$(KERNELPATH).tar.gz ; \
+ rm $(TOPDIR)/../$(KERNELPATH).tar.gz
++
++
++
++#
++# Burn Linux Image for ArmBoot using the bdi2000
++#
++burn burn_zImage:
++ python ../hwtester/burner.py arch/arm/boot/zImage 0x40000
++
++publish: arch/arm/boot/zImage
++ cp arch/arm/boot/zImage /tftpboot/bdi/zImage.testing
+--- linux-2.4.21/arch/arm/Makefile~arm-noshortloads
++++ linux-2.4.21/arch/arm/Makefile
+@@ -55,8 +55,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)
+@@ -289,7 +289,7 @@
+ arch/arm/kernel arch/arm/mm arch/arm/lib: dummy
+ $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)
+
+-bzImage zImage zinstall Image xipImage bootpImage install: vmlinux
++bzImage zImage zinstall Image xipImage bootpImage: vmlinux
+ @$(MAKEBOOT) $@
+
+ CLEAN_FILES += \
+--- linux-2.4.21/arch/arm/config.in~pm
++++ linux-2.4.21/arch/arm/config.in
+@@ -152,6 +152,7 @@
+ 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 ' M und N Ramses' CONFIG_ARCH_RAMSES $CONFIG_ARCH_PXA
+ dep_bool ' Trizeps-II MT6N' CONFIG_ARCH_TRIZEPS2 $CONFIG_ARCH_PXA
+
+ if [ "$CONFIG_ARCH_PXA_CERF" = "y" ]; then
+@@ -586,6 +587,7 @@
+ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ dep_bool 'Power Management support (experimental)' CONFIG_PM $CONFIG_EXPERIMENTAL
++dep_bool 'Advanced power management emulation support' CONFIG_APM $CONFIG_PM
+ dep_tristate 'RISC OS personality' CONFIG_ARTHUR $CONFIG_CPU_32
+ string 'Default kernel command string' CONFIG_CMDLINE ""
+
+--- /dev/null
++++ linux-2.4.21/arch/arm/def-configs/ramses
+@@ -0,0 +1,1128 @@
++#
++# 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_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
++
++#
++# 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_RAMSES=y
++# CONFIG_ARCH_TRIZEPS2 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_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_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_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=y
++CONFIG_ZBOOT_ROM_TEXT=00040000
++CONFIG_ZBOOT_ROM_BSS=a00c0000
++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
++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_APM=y
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="debug"
++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_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 is not set
++CONFIG_MTD_RAMSES=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
++# 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=m
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD is not set
++CONFIG_BLK_STATS=y
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_NETLINK_DEV=m
++# 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=m
++CONFIG_NET_IPGRE=m
++# 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=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 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=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=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_HERMES=m
++CONFIG_PCMCIA_HERMES=m
++# CONFIG_AIRO_CS 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
++
++#
++# 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 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 is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++CONFIG_IRDA=m
++CONFIG_IRLAN=m
++CONFIG_IRNET=m
++CONFIG_IRCOMM=m
++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=m
++CONFIG_IRPORT_SIR=m
++# 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_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_PXA_FIR=m
++
++#
++# 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=m
++CONFIG_BLK_DEV_SD=m
++CONFIG_SD_EXTRA_DEVS=4
++# 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 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_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_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_NSP32 is not set
++# CONFIG_SCSI_DEBUG is not set
++
++#
++# PCMCIA SCSI adapter support
++#
++# CONFIG_SCSI_PCMCIA 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_RAMSES_KEYB=y
++CONFIG_INPUT_RAMSES_WEDGE=y
++# 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=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_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=32
++
++#
++# 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=m
++CONFIG_I2C_PROC=m
++# CONFIG_I2C_DS1307 is not set
++CONFIG_I2C_DS1337=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_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 is not set
++# CONFIG_SCx200_GPIO is not set
++# CONFIG_AMD_PM768 is not set
++# CONFIG_NVRAM is not set
++CONFIG_RTC=m
++CONFIG_PXA_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
++
++#
++# PCMCIA character devices
++#
++# CONFIG_PCMCIA_SERIAL_CS is not set
++# CONFIG_SYNCLINK_CS 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 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
++# CONFIG_VIDEO_CYBERPRO 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
++
++#
++# 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=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=m
++# CONFIG_CRAMFS_LINEAR is not set
++# CONFIG_CRAMFS_LINEAR_XIP is not set
++# CONFIG_ROOT_CRAMFS_LINEAR 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=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=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 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=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_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_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 is not set
++# 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=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
++
++#
++# USB support
++#
++CONFIG_USB=m
++# CONFIG_USB_DEBUG is not set
++CONFIG_USB_DEVICEFS=y
++# CONFIG_USB_BANDWIDTH is not set
++# CONFIG_USB_EHCI_HCD is not set
++# CONFIG_USB_UHCI is not set
++# CONFIG_USB_UHCI_ALT is not set
++# CONFIG_USB_OHCI is not set
++# CONFIG_USB_OHCI_SA1111 is not set
++CONFIG_USB_SL811HS_ALT=m
++CONFIG_USB_AUDIO=m
++CONFIG_USB_EMI26=m
++# CONFIG_USB_BLUETOOTH is not set
++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 is not set
++CONFIG_USB_PRINTER=m
++CONFIG_USB_HID=m
++CONFIG_USB_HIDINPUT=y
++CONFIG_USB_HIDDEV=y
++CONFIG_USB_KBD=m
++# 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_VICAM=m
++# CONFIG_USB_DSBR is not set
++# CONFIG_USB_DABUSB 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 is not set
++# 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 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 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
++
++#
++# Library routines
++#
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
+--- linux-2.4.21/arch/arm/mach-pxa/Makefile~pm
++++ linux-2.4.21/arch/arm/mach-pxa/Makefile
+@@ -14,8 +14,11 @@
+ obj-n :=
+ obj- :=
+
+-export-objs := generic.o irq.o dma.o sa1111.o \
+- usb_ctl.o usb_recv.o usb_send.o
++export-objs := apm.o generic.o irq.o dma.o sa1111.o \
++ usb_ctl.o usb_recv.o usb_send.o pm.o
++
++
++export-objs += ramses.o
+
+ # Common support (must be linked before board specific support)
+ obj-y += generic.o irq.o dma.o
+@@ -27,6 +30,7 @@
+ obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
+ obj-$(CONFIG_ARCH_PXA_CERF) += cerf.o
+ obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
++obj-$(CONFIG_ARCH_RAMSES) += ramses.o
+ obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o
+
+ # Support for blinky lights
+@@ -48,6 +52,7 @@
+
+ # Misc features
+ obj-$(CONFIG_PM) += pm.o sleep.o
++obj-$(CONFIG_APM) += apm.o
+ obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o
+
+ include $(TOPDIR)/Rules.make
+--- /dev/null
++++ linux-2.4.21/arch/arm/mach-pxa/apm.c
+@@ -0,0 +1,491 @@
++/*
++ * bios-less APM driver for ARM Linux
++ * Jamey Hicks <jamey@crl.dec.com>
++ * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com)
++ *
++ * APM 1.2 Reference:
++ * Intel Corporation, Microsoft Corporation. Advanced Power Management
++ * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
++ *
++ * [This document is available from Microsoft at:
++ * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/poll.h>
++#include <linux/types.h>
++#include <linux/stddef.h>
++#include <linux/timer.h>
++#include <linux/fcntl.h>
++#include <linux/slab.h>
++#include <linux/stat.h>
++#include <linux/proc_fs.h>
++#include <linux/miscdevice.h>
++#include <linux/apm_bios.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/pm.h>
++#include <linux/kernel.h>
++#include <linux/smp_lock.h>
++
++#include <asm/system.h>
++#include <asm/hardware.h>
++
++#ifdef CONFIG_SA1100_H3XXX
++#include <asm/arch/h3600_hal.h>
++#endif
++
++#include "pm-common.c"
++
++struct apm_bios_info apm_bios_info = {
++ /* this driver simulates APM version 1.2 */
++ version: 0x102,
++ flags: APM_32_BIT_SUPPORT
++};
++
++/*
++ * The apm_bios device is one of the misc char devices.
++ * This is its minor number.
++ */
++#define APM_MINOR_DEV 134
++
++/*
++ * See Documentation/Config.help for the configuration options.
++ *
++ * Various options can be changed at boot time as follows:
++ * (We allow underscores for compatibility with the modules code)
++ * apm=on/off enable/disable APM
++ * [no-]power[-_]off power off on shutdown
++ */
++
++/*
++ * Maximum number of events stored
++ */
++#define APM_MAX_EVENTS 10
++
++/*
++ * The per-file APM data
++ */
++struct apm_user {
++ int magic;
++ struct apm_user * next;
++ int suser: 1;
++ int suspend_wait: 1;
++ int suspend_result;
++ int suspends_pending;
++ int standbys_pending;
++ int suspends_read;
++ int standbys_read;
++ int event_head;
++ int event_tail;
++ apm_event_t events[APM_MAX_EVENTS];
++};
++
++/*
++ * The magic number in apm_user
++ */
++#define APM_BIOS_MAGIC 0x4101
++
++/*
++ * Local variables
++ */
++
++#ifdef CONFIG_APM_RTC_IS_GMT
++#define clock_cmos_diff 0
++#define got_clock_diff 1
++#endif
++static int apm_disabled;
++#ifdef CONFIG_SMP
++static int power_off;
++#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);
++static struct apm_user * user_list = NULL;
++
++static char driver_version[] = "1.13"; /* no spaces */
++
++typedef struct lookup_t {
++ int key;
++ char * msg;
++} lookup_t;
++
++static const lookup_t error_table[] = {
++/* N/A { APM_SUCCESS, "Operation succeeded" }, */
++ { APM_DISABLED, "Power management disabled" },
++ { APM_CONNECTED, "Real mode interface already connected" },
++ { APM_NOT_CONNECTED, "Interface not connected" },
++ { APM_16_CONNECTED, "16 bit interface already connected" },
++/* N/A { APM_16_UNSUPPORTED, "16 bit interface not supported" }, */
++ { APM_32_CONNECTED, "32 bit interface already connected" },
++ { APM_32_UNSUPPORTED, "32 bit interface not supported" },
++ { APM_BAD_DEVICE, "Unrecognized device ID" },
++ { APM_BAD_PARAM, "Parameter out of range" },
++ { APM_NOT_ENGAGED, "Interface not engaged" },
++ { APM_BAD_FUNCTION, "Function not supported" },
++ { APM_RESUME_DISABLED, "Resume timer disabled" },
++ { APM_BAD_STATE, "Unable to enter requested state" },
++/* N/A { APM_NO_EVENTS, "No events pending" }, */
++ { APM_NO_ERROR, "BIOS did not set a return code" },
++ { APM_NOT_PRESENT, "No APM present" }
++};
++#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
++
++static int (*apm_get_power_status)(u_char *ac_line_status,
++ u_char *battery_status,
++ u_char *battery_flag,
++ u_char *battery_percentage,
++ u_short *battery_life) = 0;
++
++void apm_register_get_power_status( int (*fn)(u_char *ac_line_status,
++ u_char *battery_status,
++ u_char *battery_flag,
++ u_char *battery_percentage,
++ u_short *battery_life))
++{
++ apm_get_power_status = fn;
++}
++
++static int queue_empty(struct apm_user *as)
++{
++ return as->event_head == as->event_tail;
++}
++
++static apm_event_t get_queued_event(struct apm_user *as)
++{
++ as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
++ return as->events[as->event_tail];
++}
++
++static int check_apm_user(struct apm_user *as, const char *func)
++{
++ if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
++ printk(KERN_ERR "apm: %s passed bad filp\n", func);
++ return 1;
++ }
++ return 0;
++}
++
++static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
++{
++ struct apm_user * as;
++ int i;
++ apm_event_t event;
++ DECLARE_WAITQUEUE(wait, current);
++
++ as = fp->private_data;
++ if (check_apm_user(as, "read"))
++ return -EIO;
++ if (count < sizeof(apm_event_t))
++ return -EINVAL;
++ if (queue_empty(as)) {
++ if (fp->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++ add_wait_queue(&apm_waitqueue, &wait);
++ printk("do_read: waiting\n");
++repeat:
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (queue_empty(as) && !signal_pending(current)) {
++ schedule();
++ goto repeat;
++ }
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&apm_waitqueue, &wait);
++ }
++ 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;
++ return -EFAULT;
++ }
++ switch (event) {
++ case APM_SYS_SUSPEND:
++ case APM_USER_SUSPEND:
++ as->suspends_read++;
++ break;
++
++ case APM_SYS_STANDBY:
++ case APM_USER_STANDBY:
++ as->standbys_read++;
++ break;
++ }
++ buf += sizeof(event);
++ i -= sizeof(event);
++ }
++ if (i < count)
++ return count - i;
++ if (signal_pending(current))
++ return -ERESTARTSYS;
++ return 0;
++}
++
++static unsigned int do_poll(struct file *fp, poll_table * wait)
++{
++ struct apm_user * as;
++
++ as = fp->private_data;
++ if (check_apm_user(as, "poll"))
++ return 0;
++ poll_wait(fp, &apm_waitqueue, wait);
++ if (!queue_empty(as))
++ return POLLIN | POLLRDNORM;
++ return 0;
++}
++
++static int do_ioctl(struct inode * inode, struct file *filp,
++ u_int cmd, u_long arg)
++{
++ struct apm_user * as;
++
++ as = filp->private_data;
++ if (check_apm_user(as, "ioctl"))
++ return -EIO;
++ if (!as->suser)
++ return -EPERM;
++ switch (cmd) {
++ case APM_IOC_SUSPEND:
++ pm_suggest_suspend();
++ break;
++ default:
++ printk("//hs %x\n", cmd);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int do_release(struct inode * inode, struct file * filp)
++{
++ struct apm_user * as;
++
++ as = filp->private_data;
++ if (check_apm_user(as, "release"))
++ return 0;
++ filp->private_data = NULL;
++ lock_kernel();
++ unlock_kernel();
++ kfree(as);
++ return 0;
++}
++
++static int do_open(struct inode * inode, struct file * filp)
++{
++ struct apm_user * as;
++
++ as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
++ if (as == NULL) {
++ printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
++ sizeof(*as));
++ return -ENOMEM;
++ }
++ 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;
++ /*
++ * XXX - this is a tiny bit broken, when we consider BSD
++ * process accounting. If the device is opened by root, we
++ * instantly flag that we used superuser privs. Who knows,
++ * we might close the device immediately without doing a
++ * privileged operation -- cevans
++ */
++ as->suser = capable(CAP_SYS_ADMIN);
++ as->next = user_list;
++ user_list = as;
++ filp->private_data = as;
++ return 0;
++}
++
++static int apm_get_info(char *buf, char **start, off_t fpos, int length)
++{
++ char * p;
++ unsigned short dx;
++ unsigned short error;
++ unsigned char ac_line_status = 0xff;
++ unsigned char battery_status = 0xff;
++ unsigned char battery_flag = 0xff;
++ unsigned char percentage = 0xff;
++ int time_units = -1;
++ char *units = "?";
++
++ p = buf;
++
++ if ( (smp_num_cpus == 1) &&
++ apm_get_power_status &&
++ !(error = apm_get_power_status(&ac_line_status,
++ &battery_status, &battery_flag, &percentage, &dx))) {
++ if (apm_bios_info.version > 0x100) {
++ if (dx != 0xffff) {
++ units = (dx & 0x8000) ? "min" : "sec";
++ time_units = dx & 0x7fff;
++ }
++ }
++ }
++ /* Arguments, with symbols from linux/apm_bios.h. Information is
++ from the Get Power Status (0x0a) call unless otherwise noted.
++
++ 0) Linux driver version (this will change if format changes)
++ 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
++ 2) APM flags from APM Installation Check (0x00):
++ bit 0: APM_16_BIT_SUPPORT
++ bit 1: APM_32_BIT_SUPPORT
++ bit 2: APM_IDLE_SLOWS_CLOCK
++ bit 3: APM_BIOS_DISABLED
++ bit 4: APM_BIOS_DISENGAGED
++ 3) AC line status
++ 0x00: Off-line
++ 0x01: On-line
++ 0x02: On backup power (BIOS >= 1.1 only)
++ 0xff: Unknown
++ 4) Battery status
++ 0x00: High
++ 0x01: Low
++ 0x02: Critical
++ 0x03: Charging
++ 0x04: Selected battery not present (BIOS >= 1.2 only)
++ 0xff: Unknown
++ 5) Battery flag
++ bit 0: High
++ bit 1: Low
++ bit 2: Critical
++ bit 3: Charging
++ bit 7: No system battery
++ 0xff: Unknown
++ 6) Remaining battery life (percentage of charge):
++ 0-100: valid
++ -1: Unknown
++ 7) Remaining battery life (time units):
++ Number of remaining minutes or seconds
++ -1: Unknown
++ 8) min = minutes; sec = seconds */
++
++ p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
++ driver_version,
++ (apm_bios_info.version >> 8) & 0xff,
++ apm_bios_info.version & 0xff,
++ apm_bios_info.flags,
++ ac_line_status,
++ battery_status,
++ battery_flag,
++ percentage,
++ time_units,
++ units);
++
++ return p - buf;
++}
++
++#ifndef MODULE
++static int __init apm_setup(char *str)
++{
++ int invert;
++
++printk("//hs apm_setup\n");
++ 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, "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,
++ poll: do_poll,
++ ioctl: do_ioctl,
++ open: do_open,
++ release: do_release,
++};
++
++static struct miscdevice apm_device = {
++ APM_MINOR_DEV,
++ "apm_bios",
++ &apm_bios_fops
++};
++
++#define APM_INIT_ERROR_RETURN return -1
++
++/*
++ * 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
++ * than the fact that we don't trust the APM BIOS. This way,
++ * most common APM BIOS problems that lead to protection errors
++ * etc will have at least some level of being contained...
++ *
++ * In short, if something bad happens, at least we have a choice
++ * of just killing the apm thread..
++ */
++static int __init apm_init(void)
++{
++ if (apm_bios_info.version == 0) {
++ printk(KERN_INFO "apm: BIOS not found.\n");
++ APM_INIT_ERROR_RETURN;
++ }
++ printk(KERN_INFO
++ "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
++ ((apm_bios_info.version >> 8) & 0xff),
++ (apm_bios_info.version & 0xff),
++ apm_bios_info.flags,
++ driver_version);
++
++ if (apm_disabled) {
++ printk(KERN_NOTICE "apm: disabled on user request.\n");
++ APM_INIT_ERROR_RETURN;
++ }
++
++ if (PM_IS_ACTIVE()) {
++ printk(KERN_NOTICE "apm: overridden by ACPI.\n");
++ APM_INIT_ERROR_RETURN;
++ }
++ pm_active = 1;
++
++ create_proc_info_entry("apm", 0, NULL, apm_get_info);
++
++ misc_register(&apm_device);
++
++ return 0;
++}
++
++module_init(apm_init);
++
++#ifdef MODULE
++static void __exit apm_exit(void)
++{
++ misc_deregister(&apm_device);
++ remove_proc_entry("apm", NULL);
++ if (power_off)
++ pm_power_off = NULL;
++ exit_kapmd = 1;
++ while (kapmd_running)
++ schedule();
++ pm_active = 0;
++}
++
++module_exit(apm_exit);
++
++MODULE_AUTHOR("Jamey Hicks, pulling bits from original by Stephen Rothwell");
++MODULE_DESCRIPTION("A minimal emulation of APM");
++MODULE_PARM(power_off, "i");
++MODULE_PARM_DESC(power_off, "Enable power off");
++#endif
+--- linux-2.4.21/arch/arm/mach-pxa/cpu-pxa.c~ramses-corevolt
++++ linux-2.4.21/arch/arm/mach-pxa/cpu-pxa.c
+@@ -39,7 +39,7 @@
+
+ #include <asm/hardware.h>
+
+-#define DEBUGGING 1
++#define DEBUGGING 0
+
+ #if DEBUGGING
+ static unsigned int freq_debug = DEBUGGING;
+@@ -52,6 +52,7 @@
+ unsigned int khz;
+ unsigned int cccr;
+ unsigned int pxbus;
++ unsigned int corevolt;
+ } pxa_freqs_t;
+
+ #define CCLKCFG_TURBO 0x1
+@@ -79,23 +80,23 @@
+
+ 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 */
++ {199100, 0x141, 99, 115}, /* mem= 99, run=199, turbo=199, PXbus= 99 */
++ {298600, 0x1c1, 99, 125}, /* mem= 99, run=199, turbo=298, PXbus= 99 */
++ {398100, 0x241, 99, 135}, /* 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 */
++ { 99000, 0x121, 50, 105}, /* mem= 99, run= 99, turbo= 99, PXbus= 50 */
++OC( {118000, 0x122, 59, 115},)/* mem=118, run=118, turbo=118, PXbus= 59 OC'd mem */
++ {199100, 0x141, 99, 115}, /* mem= 99, run=199, turbo=199, PXbus= 99 */
++OC( {236000, 0x142,118, 125},)/* mem=118, run=236, turbo=236, PXbus=118 OC'd mem */
++ {298600, 0x1c1, 99, 125}, /* mem= 99, run=199, turbo=298, PXbus= 99 */
++OC( {354000, 0x1c2,118, 135},)/* mem=118, run=236, turbo=354, PXbus=118 OC'd mem */
++ {398099, 0x241, 99, 135}, /* mem= 99, run=199, turbo=398, PXbus= 99 */
++ {398100, 0x161,196, 135}, /* mem= 99, run=398, turbo=398, PXbus=196 */
++OC( {471000, 0x162,236, 150},)/* mem=118, run=471, turbo=471, PXbus=236 OC'd mem/core/bus */
+ {0,0}
+ };
+
+@@ -109,7 +110,7 @@
+ int i=0;
+ while( pxa_valid_freqs[i].khz)
+ {
+- if( pxa_valid_freqs[i].khz == khz)
++ if (pxa_valid_freqs[i].khz == khz)
+ return &pxa_valid_freqs[i];
+ i++;
+ }
+@@ -141,14 +142,17 @@
+ void *ramstart = phys_to_virt(0xa0000000);
+ pxa_freqs_t *freq_info;
+
+- if( ! supported) return;
++ if (! supported) return;
+
+ freq_info = pxa_get_freq_info( khz);
+
+- if( ! freq_info) return;
++ if (! freq_info) return;
++
++ if (freq_info->corevolt > ramses_corevolt_shadow)
++ ramses_set_corevolt(freq_info->corevolt);
+
+ CCCR = freq_info->cccr;
+- if( freq_debug)
++ if (freq_debug)
+ printk(KERN_INFO "Changing CPU frequency to %d Mhz (PXbus=%dMhz).\n",
+ khz/1000, freq_info->pxbus);
+
+@@ -184,6 +188,9 @@
+ : "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart)
+ : "r4", "r5");
+ local_irq_restore(flags);
++
++ if (freq_info->corevolt < ramses_corevolt_shadow)
++ ramses_set_corevolt(freq_info->corevolt);
+ }
+
+ static int pxa_init_freqs( void)
+@@ -191,19 +198,19 @@
+ int cpu_ver;
+ asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver));
+
+- if( (cpu_ver & 0xf) <= PXA250_REV_A1)
++ if ((cpu_ver & 0xf) <= PXA250_REV_A1)
+ {
+ return 0;
+ }
+
+- if( (cpu_ver & 0xf) <= PXA250_REV_B2)
++ if ((cpu_ver & 0xf) <= PXA250_REV_B2)
+ {
+- if( freq_debug) printk(KERN_INFO "Using PXA250 frequency points.\n");
++ 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");
++ if (freq_debug) printk(KERN_INFO "Using PXA255 frequency points.\n");
+ pxa_valid_freqs = pxa255_valid_freqs;
+ }
+
+@@ -212,24 +219,23 @@
+
+ static int __init pxa_clk_init(void)
+ {
+- if( pxa_init_freqs())
++ if (pxa_init_freqs())
+ {
+- if( freq_debug) printk(KERN_INFO "Registering CPU frequency change support.\n");
++ 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");
++ 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);
+ }
++ cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed);
+
+ return 0;
+ }
+--- linux-2.4.21/arch/arm/mach-pxa/generic.c~pm
++++ linux-2.4.21/arch/arm/mach-pxa/generic.c
+@@ -28,6 +28,11 @@
+ #include <asm/pgtable.h>
+ #include <asm/mach/map.h>
+
++#ifdef CONFIG_PXA_RTC_HACK
++#include <asm/setup.h>
++#include <linux/bootmem.h>
++#endif
++
+ #include "generic.h"
+
+ /*
+@@ -139,4 +144,41 @@
+ {
+ iotable_init(standard_io_desc);
+ get_clk_frequency_khz( 1);
++#ifdef CONFIG_PXA_RTC_HACK
++ pxa_rtc_hack_init();
++#endif
++}
++
++
++
++#ifdef CONFIG_PXA_RTC_HACK
++unsigned long *save_RCNR = 0;
++
++void pxa_rtc_hack_init(void)
++{
++ /*
++ This has to be here since I guess the bootmem API is the
++ right choice to allocate the memory during boot
++ place. And we are sure that timer iqr is not already
++ running.
++ - Christian Pellegin <chri@infis.univ.trieste.it>
++ */
++ unsigned long pxa_rtc_hack = 0;
++
++ pxa_rtc_hack = meminfo.bank[meminfo.nr_banks-1].start +
++ meminfo.bank[meminfo.nr_banks-1].size -
++ PAGE_SIZE;
++ reserve_bootmem(pxa_rtc_hack, PAGE_SIZE);
++ printk("Reserved %ld bytes at %lx for RTC hack\n",
++ PAGE_SIZE, pxa_rtc_hack);
++ save_RCNR = (unsigned long *) phys_to_virt(pxa_rtc_hack);
++ if ( (save_RCNR[0] ^ save_RCNR[1]) == 0xffffffff ) {
++ printk("Restoring saved RCNR value to %ld (from %lx)\n",
++ save_RCNR[0], (unsigned long) save_RCNR);
++ RCNR = save_RCNR[0];
++ }
++ else {
++ printk("No valid saved RCNR value found at %lx\n", (unsigned long) save_RCNR);
++ }
+ }
++#endif /* CONFIG_PXA_RTC_HACK */
+--- linux-2.4.21/arch/arm/mach-pxa/generic.h~pm
++++ linux-2.4.21/arch/arm/mach-pxa/generic.h
+@@ -17,3 +17,7 @@
+ mi->bank[__nr].size = (__size), \
+ mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27)
+
++#ifdef CONFIG_PXA_RTC_HACK
++void pxa_rtc_hack_init(void);
++extern unsigned long *save_RCNR;
++#endif
+--- /dev/null
++++ linux-2.4.21/arch/arm/mach-pxa/pm-common.c
+@@ -0,0 +1,285 @@
++/*
++ * 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>
++
++
++
++static char pm_helper_path[128] = "/etc/apm/apmd_proxy";
++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");
++
++ if (action == PM_RESUME)
++ argv[i++]="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
++
++/*
++ * 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},
++ {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
++
+--- linux-2.4.21/arch/arm/mach-pxa/pm.c~pm
++++ linux-2.4.21/arch/arm/mach-pxa/pm.c
+@@ -19,6 +19,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/sysctl.h>
+ #include <linux/errno.h>
++#include <linux/module.h>
+
+ #include <asm/hardware.h>
+ #include <asm/memory.h>
+@@ -82,7 +83,7 @@
+
+ /*
+ * Temporary solution. This won't be necessary once
+- * we move pxa support into the serial/* driver
++ * we move pxa support into the serial driver
+ * Save the FF UART
+ */
+ SAVE(FFIER);
+@@ -176,7 +177,7 @@
+
+ /*
+ * Temporary solution. This won't be necessary once
+- * we move pxa support into the serial/* driver.
++ * we move pxa support into the serial driver.
+ * Restore the FF UART.
+ */
+ RESTORE(FFMCR);
+@@ -209,6 +210,12 @@
+ return virt_to_phys(sp);
+ }
+
++#ifndef CONFIG_APM
++/*
++ * This code is only needed if we don't compile in APM support.
++ * If we compile APM support in, then this code is in pm-common.c
++ */
++
+ #ifdef CONFIG_SYSCTL
+ /*
+ * ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than
+@@ -263,3 +270,6 @@
+ __initcall(pm_init);
+
+ #endif
++#endif
++
++EXPORT_SYMBOL(pm_do_suspend);
+--- linux-2.4.21/arch/arm/mach-pxa/pxa_usb.h~pxa-usb
++++ linux-2.4.21/arch/arm/mach-pxa/pxa_usb.h
+@@ -39,6 +39,7 @@
+ int pxa_usb_xmitter_avail( void );
+ int pxa_usb_send(char *buf, int len, usb_callback_t callback);
+ void sa110a_usb_send_reset(void);
++void pxa_usb_send_reset(void);
+
+ /* in usb_recev.c */
+ int pxa_usb_recv(char *buf, int len, usb_callback_t callback);
+--- /dev/null
++++ linux-2.4.21/arch/arm/mach-pxa/ramses.c
+@@ -0,0 +1,844 @@
++/*
++ * linux/arch/arm/mach-pxa/ramses.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,2003,2004 by M&N Logistik-Lösungen Online GmbH
++ * written by Holger Schurig
++ *
++ * 2001-09-13: Cliff Brake <cbrake@accelent.com>
++ * Initial code
++ *
++ * 2002-10-09: adaptions to ramses
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/ioport.h>
++#include <linux/pm.h>
++#include <linux/delay.h>
++#ifdef CONFIG_APM
++#include <linux/apm_bios.h>
++#endif
++#define USE_UCB
++//#define PFI_LED
++#define PFI_TURNOFF
++
++#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-pxa/pxa-regs.h>
++
++#ifdef USE_UCB
++#include "../drivers/misc/ucb1x00.h"
++#endif
++
++#include "generic.h"
++
++
++/* shadow registers for write only registers */
++u16 ramses_control_shadow =
++ RAMSES_CONTROL_LED_BLUE_ +
++ RAMSES_CONTROL_LED_ORANGE_ +
++ RAMSES_CONTROL_SCANNER_WAKE_ +
++ RAMSES_CONTROL_SCANNER_TRIG_;
++
++/* various flags the change the behavior of the kernel */
++unsigned int ramses_flags =
++ RAMSES_FLAGS_KEY_SCAN +
++ RAMSES_FLAGS_KEY_SUSPEND +
++ RAMSES_FLAGS_KEY_OFF;
++
++
++/******************************************************************/
++/* Corevoltage settings */
++/******************************************************************/
++
++int ramses_corevolt_shadow = 150;
++
++void ramses_set_corevolt(int volt)
++{
++ int val = 0;
++ switch (volt) {
++ case 150:
++ val = 5;
++ break;
++ case 135:
++ val = 8;
++ break;
++ case 125:
++ val = 10;
++ break;
++ case 115:
++ val = 12;
++ break;
++ case 105:
++ val = 14;
++ break;
++ }
++ if (val) {
++ ramses_corevolt_shadow = volt;
++ RAMSES_COREVOLT = val;
++ RAMSES_CPLD_PERIPH_PWR |= CORE_VAR_EN;
++ }
++}
++
++
++/******************************************************************/
++/* LCD stuff */
++/******************************************************************/
++
++u16 ramses_lcd_type;
++
++void ramses_lcd_power_on(void)
++{
++ //printk("--> ramses_lcd_power_on\n");
++
++ /* 1. VCC */
++ RAMSES_CPLD_LCD |= RAMSES_LCD_VCC;
++
++ /* 2. Signal */
++
++ /* 3. the PWM */
++ CKEN |= (CKEN0_PWM0 | CKEN1_PWM1);
++
++ /* 4. nDISPOFF (done at backlight_on time) */
++ RAMSES_CPLD_LCD |= RAMSES_LCD_DISPOFF;
++}
++
++
++void ramses_lcd_power_off(void)
++{
++ //printk("--> ramses_lcd_power_off\n");
++ if (RAMSES_CPLD_LCD & RAMSES_LCD_DISPOFF) {
++ //printk("--> turn bl off first\n");
++ ramses_lcd_backlight_off();
++ }
++
++ /* 1. nDISPOFF (just to be sure) */
++ RAMSES_CPLD_LCD &= ~RAMSES_LCD_DISPOFF;
++
++ // for Torisan: wait until all has been sent out
++ if (ramses_lcd_type == 2) {
++ int i;
++ for (i=0; i<33; i++)
++ udelay(1500);
++ }
++
++ /* 2. disable the PWM */
++ set_GPIO_mode(GPIO16_PWM0 | GPIO_OUT);
++ set_GPIO_mode(GPIO17_PWM1 | GPIO_OUT);
++ CKEN &= ~(CKEN0_PWM0 | CKEN1_PWM1);
++
++ /* 3. SIGNAL */
++
++ /* 4. VCC */
++ RAMSES_CPLD_LCD &= ~RAMSES_LCD_VCC;
++}
++
++
++void ramses_lcd_backlight_on(void)
++{
++ int i;
++
++ //printk("--> ramses_lcd_backlight_on\n");
++ if ((ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT) != 0)
++ return;
++ //printk(" state: %d\n", ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT);
++
++ set_GPIO_mode(GPIO17_PWM1 | GPIO_OUT);
++
++ /* 4. nDISPOFF */
++ RAMSES_CPLD_LCD |= RAMSES_LCD_DISPOFF;
++
++ /* Backlight can be turned on at any time */
++ RAMSES_LCD_BLIGHT_ON();
++
++ for (i=0; i<33; i++)
++ udelay(1500);
++ set_GPIO_mode(GPIO16_PWM0_MD);
++ set_GPIO_mode(GPIO17_PWM1_MD);
++}
++
++
++void ramses_lcd_backlight_off(void)
++{
++ int i;
++
++ //printk("--> ramses_lcd_backlight_off\n");
++ if ((ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT) == 0)
++ return;
++ //printk(" state: %d\n", ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT);
++
++ set_GPIO_mode(GPIO17_PWM1 | GPIO_OUT);
++ for (i=0; i<100; i++)
++ udelay(1500);
++
++ /* Backlight can be turned off at any time */
++ RAMSES_LCD_BLIGHT_OFF();
++ udelay(1500);
++
++ /* 1. nDISPOFF */
++ if (ramses_lcd_type != 2)
++ RAMSES_CPLD_LCD &= ~RAMSES_LCD_DISPOFF;
++
++ //set_GPIO_mode(GPIO16_PWM0 | GPIO_IN);
++ //set_GPIO_mode(GPIO17_PWM1 | GPIO_IN);
++}
++
++
++void ramses_lcd_set_brightness(int b)
++{
++ if (b > 255) b = 255;
++ if (b < 0) b = 0;
++ PWM_PWDUTY1 = 510-(b<<1);
++}
++
++
++int ramses_lcd_get_brightness(void)
++{
++ return 255-(PWM_PWDUTY1 >> 1);
++}
++
++
++void ramses_lcd_set_contrast(int c)
++{
++ if (c > 255) c = 255;
++ if (c < 0) c = 0;
++ PWM_PWDUTY0 = 542-c;
++}
++
++
++int ramses_lcd_get_contrast(void)
++{
++ return 542-PWM_PWDUTY0;
++}
++
++
++void ramses_lcd_set_intensity(int i)
++{
++ //printk("--> ramses_lcd_set_intensity(%d)\n", i);
++ if (i) {
++ ramses_lcd_backlight_on();
++ } else {
++ ramses_lcd_backlight_off();
++ }
++}
++
++
++int ramses_lcd_get_intensity(void)
++{
++ return ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT;
++}
++
++
++
++
++
++/******************************************************************/
++/* HDQ communication */
++/******************************************************************/
++
++#define GPIO_HDQ 2
++
++#define HDQ_LO GPCR(GPIO_HDQ) = GPIO_bit(GPIO_HDQ)
++#define HDQ_HI GPSR(GPIO_HDQ) = GPIO_bit(GPIO_HDQ)
++#define HDQ_GET (GPLR(GPIO_HDQ) & (1 << GPIO_HDQ))
++
++#define MAXLOOPS 800
++#define MAXTRIES 3
++
++
++static void hdq_break(void)
++{
++ HDQ_LO;
++ set_GPIO_mode(GPIO_HDQ | GPIO_OUT);
++ udelay(220);
++ HDQ_HI;
++ udelay(50);
++}
++
++
++/**
++ * Send data on the 1-bit wire.
++ *
++ * LSB first. Depending on the bit, do the low phase short or
++ * small. The used timings in usec's are made so that our send
++ * stuff has exactly the timing that the BQ2050 battery sends
++ * us back.
++*/
++static void hdq_put_data(unsigned char cmd)
++{
++ unsigned char mask = 1;
++
++ HDQ_HI;
++ set_GPIO_mode(GPIO_HDQ | GPIO_OUT);
++
++ while (1) {
++ HDQ_LO;
++ udelay(cmd & mask ? 37 : 115);
++ HDQ_HI;
++ udelay(cmd & mask ? 163 : 85);
++ if (mask == 0x80) break;
++ mask = mask << 1;
++ }
++ set_GPIO_mode(GPIO_HDQ | GPIO_IN);
++}
++
++
++/**
++ * Receive data on the 1-bit wire.
++ *
++ * Little state-machine with two states (yuck) that measures the time
++ * in the low-state. If it exceeds some value, then the bit was a 0,
++ * otherwise it's a 1.
++*/
++static int hdq_get_data(void)
++{
++ enum { ST_WAITLOW, ST_LOW };
++
++ int i;
++ int lastlow = 0;
++ int state = ST_WAITLOW;
++ unsigned char mask = 1;
++ unsigned char d = 0;
++
++ for (i=0; i<MAXLOOPS; i++) {
++ if (state==ST_WAITLOW) {
++ if (HDQ_GET == 0) {
++ lastlow = i;
++ state = ST_LOW;
++ }
++ } else
++ if (state == ST_LOW) {
++ if (HDQ_GET) {
++ // 34 must be changed if the udelay(2) changes!
++ if (i-lastlow < 34) {
++ d = d | mask;
++ }
++ if (mask == 0x80) break;
++ mask = mask << 1;
++ state = ST_WAITLOW;
++ }
++ }
++ udelay(2);
++ }
++ if (i==MAXLOOPS) {
++ //printk("no respone after %d\n", i);
++ return -1;
++ } else {
++ //printk("done after %d: %d %x\n", i, d, d);
++ return d;
++ }
++}
++
++
++static int hdq_get_reg_once(unsigned char reg)
++{
++ int d = -1;
++ int i;
++
++ reg &= 0x7f;
++
++ for (i=0; i<MAXTRIES; i++) {
++ hdq_break();
++ hdq_put_data(reg);
++ d = hdq_get_data();
++ if (d != -1)
++ break;
++ //printk("hdq_get_reg_once try again: %d\n", i);
++ }
++
++ return d;
++}
++
++/**
++ * The HDQ protocol communication is so bad that we can't really
++ * be sure that we got something usable. So we call hdq_get_reg_once()
++ * twice and compare if we got the same value twice. If not, we try
++ * again. And again, and again ... up to MAXTRIES times.
++ */
++int ramses_hdq_get_reg(unsigned char reg)
++{
++ int i,d1,d2;
++
++ d1 = hdq_get_reg_once(reg);
++ for (i=0; i<MAXTRIES; i++) {
++ d2 = hdq_get_reg_once(reg);
++ if (d1 == d2)
++ return d2;
++ d1 = d2;
++ }
++ printk("no response from battery\n");
++ return -1;
++}
++
++
++
++/******************************************************************/
++/* Power Management */
++/******************************************************************/
++
++#ifdef CONFIG_PM
++static int
++ramses_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
++{
++ static int old_shadow;
++ static int old_ctrl0;
++ static int old_ctrl1;
++ static int old_perval0;
++ static int old_perval1;
++ static int old_duty0;
++ static int old_duty1;
++
++ switch (req) {
++ case PM_SUSPEND:
++ old_shadow = ramses_control_shadow;
++ old_ctrl0 = PWM_CTRL0;
++ old_ctrl1 = PWM_CTRL1;
++ old_perval0 = PWM_PERVAL0;
++ old_perval1 = PWM_PERVAL1;
++ old_duty0 = PWM_PWDUTY0;
++ old_duty1 = PWM_PWDUTY1;
++
++ // RAMSES_LED_BLUE_OFF();
++ // RAMSES_LED_ORANGE_OFF();
++ RAMSES_UART_OFF();
++ // RAMSES_SCANNER_OFF();
++ // RAMSES_USB_BUS_OFF();
++ // printk("shadow: %08x -> %08x\n", old_shadow, ramses_control_shadow);
++
++ RAMSES_CPLD_PERIPH_PWR &= ~PER_PWR_EN;
++ break;
++
++ case PM_RESUME:
++ RAMSES_CPLD_PERIPH_PWR |= PER_PWR_EN;
++ ramses_control_shadow = old_shadow;
++ PWM_CTRL0 = old_ctrl0;
++ PWM_CTRL1 = old_ctrl1;
++ PWM_PERVAL0 = old_perval0;
++ PWM_PERVAL1 = old_perval1;
++ PWM_PWDUTY0 = old_duty0;
++ PWM_PWDUTY1 = old_duty1;
++
++ break;
++ }
++ return 0;
++}
++
++#endif
++
++
++
++static void pf_interrupt(int irq, void *dummy, struct pt_regs *fp)
++{
++#ifdef PFI_LED
++ RAMSES_LED_BLUE_ON();
++ RAMSES_LED_ORANGE_ON();
++#endif
++#ifdef PFI_TURNOFF
++ // Make sure we can't be turned on by setting low onto the CPLD's columns
++ RAMSES_CPLD_KB_COL_LOW = 0;
++ RAMSES_CPLD_KB_COL_HIGH = 0;
++
++ // turn power off
++ RAMSES_POWER_OFF();
++
++ // wait until VCC fades
++ while (1) { }
++#endif
++}
++
++
++void ramses_shut_off(void)
++{
++ // Make sure we can't be turned on by setting low onto the CPLD's columns
++ RAMSES_CPLD_KB_COL_LOW = 0;
++ RAMSES_CPLD_KB_COL_HIGH = 0;
++ //printk("--> ramses_shut_off calling ramses_lcd_backlight_off\n");
++ ramses_lcd_backlight_off();
++ //printk("--> ramses_shut_off calling ramses_lcd_power_off\n");
++ ramses_lcd_power_off();
++
++ // turn power off
++ RAMSES_POWER_OFF();
++
++ // wait until voltage fades
++ while (1) {}
++}
++
++
++
++
++#ifdef CONFIG_APM
++static int ramses_get_power_status(u_char *ac_line_status,
++ u_char *battery_status,
++ u_char *battery_flag,
++ u_char *battery_percentage,
++ u_short *battery_life)
++{
++#ifdef USE_UCB
++ int adc3;
++ struct ucb1x00 *ucb = ucb1x00_get();
++
++ ucb1x00_adc_enable(ucb);
++ adc3 = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD3, 0);
++ ucb1x00_adc_disable(ucb);
++
++ /*
++ * when charged: 0..430
++ * when discharging: 0..340
++ */
++
++#define CHG_LO 165
++#define CHG_HI 420
++#define OFF_LO 60
++#define OFF_HI 350
++ if ((RAMSES_CPLD_MISC_STATUS & RAMSES_CHG_STS) == 0) {
++ // in Docking-Station
++ if (adc3 > CHG_HI) adc3 = CHG_HI;
++ if (adc3 < CHG_LO) adc3 = CHG_LO;
++ adc3 -= CHG_LO;
++ *battery_percentage = adc3 * 100 / (CHG_HI-CHG_LO);
++ *ac_line_status = 0x01;
++ } else {
++ // offline
++ if (adc3 > OFF_HI) adc3 = OFF_HI;
++ if (adc3 < OFF_LO) adc3 = OFF_LO;
++ adc3 -= OFF_LO;
++ *battery_percentage = adc3 * 100 / (OFF_HI-OFF_LO);
++ *ac_line_status = 0x00;
++ }
++
++ if (*battery_percentage > 100)
++ *battery_percentage = 100;
++
++ if (*ac_line_status) {
++ *battery_status = 3; // charging
++ *battery_flag = 1<<3;
++ } else
++ if (*battery_percentage >= 30) {
++ *battery_status = 0; // high
++ *battery_flag = 1<<0;
++ } else
++ if (*battery_percentage >= 15) {
++ *battery_status = 1; // low
++ *battery_flag = 1<<1;
++ } else {
++ *battery_status = 2; // critical
++ *battery_flag = 1<<2;
++ }
++
++ // assume 5.5 hours operation, 330 minutes
++ *battery_life = (*battery_percentage * 330 / 100) | 0x8000;
++#endif
++
++
++#ifdef USE_HDQ
++#error HDQ
++ // SAE is something like mAh * 10
++ int sae, sael;
++
++ sael = ramses_hdq_get_reg(HDQ_SAEL);
++ sae = ramses_hdq_get_reg(HDQ_SAEH);
++
++ if (sae == -1 || sael == -1) {
++ //printk("ramses: could not read HDQ_SAE\n");
++ *ac_line_status = 0xff;
++ *battery_status = 0xff;
++ *battery_flag = 0xff;
++ *battery_percentage = 0xff;
++ *battery_life = -1;
++ return 0;
++ }
++
++ sae = (sae << 16) + sael;
++ if (sae > 27000) {
++ printk("ramses: capped HDQ_SAE from %d to 27000\n", sae);
++ sae = 27000;
++ }
++
++ if (sae < 4000) {
++ *battery_status = 2; // critical
++ *battery_flag = 1<<2;
++ } else
++ if (sae < 10000) {
++ *battery_status = 1; // low
++ *battery_flag = 1<<1;
++ } else {
++ *battery_status = 0; // high
++ *battery_flag = 1<<0;
++ }
++
++ if ((RAMSES_CPLD_MISC_STATUS & RAMSES_CHG_STS) == 0) {
++ *battery_status = 3; // charging
++ *battery_flag = 1<<3;
++ *ac_line_status = 0x01; // online
++ } else {
++ *ac_line_status = 0x00; // offline
++ }
++
++ *battery_percentage = sae / 270;
++ *battery_life = (sae / 56) | 0x8000;
++#endif
++
++
++#if !defined(USE_UCB) && !defined(USE_HDQ)
++#error NONE
++ *ac_line_status = 0xff;
++ *battery_status = 0xff;
++ *battery_flag = 0xff;
++ *battery_percentage = 0xff;
++ *battery_life = -1;
++#endif
++
++ return 0;
++}
++#endif
++
++
++
++
++/******************************************************************/
++/* Initialisation */
++/******************************************************************/
++
++static struct map_desc ramses_io_desc[] __initdata = {
++ /* virtual physical length domain r w c b */
++ { RAMSES_IDE_BASE, RAMSES_IDE_PHYS, RAMSES_IDE_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
++ { RAMSES_ETH_BASE, RAMSES_ETH_PHYS, RAMSES_ETH_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
++ { RAMSES_COREVOLT_BASE, RAMSES_COREVOLT_PHYS, RAMSES_COREVOLT_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
++ { RAMSES_CPLD_BASE, RAMSES_CPLD_PHYS, RAMSES_CPLD_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
++ { RAMSES_CONTROL_BASE, RAMSES_CONTROL_PHYS, RAMSES_CONTROL_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
++ LAST_DESC
++};
++
++
++
++
++
++/*
++ * Uncompressing Linux...... done, booting the kernel.
++ * Linux version 2.4.19-rmk4-pxa1-mn ...
++ * CPU: Intel XScale-PXA250 revision 4
++ * Machine: Ramses
++ * fixup_ramses()
++ */
++
++static void __init
++fixup_ramses(struct machine_desc *desc, struct param_struct *params,
++ char **cmdline, struct meminfo *mi)
++{
++ SET_BANK (0, 0xa0000000,128*1024*1024);
++ mi->nr_banks = 1;
++}
++
++
++
++
++/*
++ * fixup_ramses()
++ * ramses_map_io()
++ */
++
++static void __init ramses_map_io(void)
++{
++ u16 smc_eeprom_read(long ioaddr, u16 location);
++
++ pxa_map_io();
++ iotable_init(ramses_io_desc);
++
++#ifdef IPAQ
++ // set power managament stuff
++ PGSR0 = GPSRx_SleepValue;
++ PGSR1 = GPSRy_SleepValue;
++ PGSR2 = GPSRz_SleepValue;
++ PWER = PWER_GPIO0 | PWER_RTC;
++ PFER = PWER_GPIO0 | PWER_RTC;
++ PRER = 0;
++#endif
++
++ ramses_lcd_type = smc_eeprom_read(RAMSES_ETH_BASE+0x300, RAMSES_LCD_TYPE_OFFSET);
++ // here we could make a special case about ramses_lcd_type == 0xffff
++ ramses_flags |= (ramses_lcd_type & RAMSES_FLAGS_LCD_FBTURN);
++}
++
++
++
++
++/*
++ * ramses_map_io()
++ * Memory clock: 99.53MHz (*27)
++ * Run Mode clock: 199.07MHz (*2)
++ * Turbo Mode clock: 398.13MHz (*2.0, active) * On node 0 totalpages: 16384
++ * zone(0): 32768 pages.
++ * zone(1): 0 pages.
++ * zone(2): 0 pages.
++ * Kernel command line: root=/dev/nfsroot ...
++ * ramses_init_irq()
++ */
++
++static void __init ramses_init_irq(void)
++{
++ set_GPIO_IRQ_edge(21, GPIO_FALLING_EDGE); // UCB 1400
++
++ RAMSES_SCANNER_OFF();
++ RAMSES_GSM_OFF();
++ RAMSES_GSM_RESET_OFF();
++ RAMSES_GSM_BOOT_OFF();
++ pxa_init_irq();
++}
++
++
++
++
++/*
++ * ramses_init_irq()
++ * Console: colour dummy device 80x30
++ * serial_console_init
++ * serial_console_setup
++ * Calibrating delay loop... 397.31 BogoMIPS
++ * Memory: 128MB = 128MB total
++ * Memory: 127872KB available (1355K code, 272K data, 112K init)
++ * Dentry cache hash table entries: 16384 (order: 5, 131072 bytes)
++ * Inode cache hash table entries: 8192 (order: 4, 65536 bytes)
++ * Mount-cache hash table entries: 2048 (order: 2, 16384 bytes)
++ * Buffer-cache hash table entries: 8192 (order: 3, 32768 bytes)
++ * Page-cache hash table entries: 32768 (order: 5, 131072 bytes)
++ * POSIX conformance testing by UNIFIX
++ * Linux NET4.0 for Linux 2.4
++ * Based upon Swansea University Computer Society NET3.039
++ * Initializing RT netlink socket
++ * ramses_init()
++ */
++
++static int __init ramses_init(void)
++{
++ unsigned int irq_gpio_pin;
++
++ // Set IRQ for Touchpanel (via UCB 1400)
++ irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ);
++ set_GPIO_IRQ_edge(irq_gpio_pin, TOUCH_PANEL_IRQ_EDGE);
++
++ // Set IRQ for Power Fail Interrupt
++ set_GPIO_IRQ_edge(1, GPIO_FALLING_EDGE);
++ request_irq(IRQ_GPIO(1), pf_interrupt, 0, "PWR FAIL", NULL);
++
++ // Setup IRQ edge for Ethernet
++ //set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(27), GPIO_RISING_EDGE);
++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(ETHERNET_IRQ), ETHERNET_IRQ_EDGE);
++
++ // Configure PWMs for LCD
++ PWM_CTRL0 = 0;
++ PWM_PERVAL0 = 512;
++ PWM_PWDUTY0 = 440;
++ PWM_CTRL1 = 0;
++ PWM_PERVAL1 = 512;
++ PWM_PWDUTY1 = 450;
++
++ // Request Memory Regions of core components
++ request_mem_region(RAMSES_CONTROL_BASE, RAMSES_CONTROL_SIZE, "Ramses Control");
++ request_mem_region(RAMSES_CPLD_BASE, RAMSES_CPLD_SIZE, "Ramses CPLD");
++ request_mem_region(RAMSES_COREVOLT_BASE, RAMSES_COREVOLT_SIZE, "Ramses Corevolt");
++
++#ifdef CONFIG_PM
++#ifdef PM_DEBUG
++ pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ramses_pm_callback, "ramses");
++#else
++ pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ramses_pm_callback);
++#endif
++ //TODO PWER (PXA255: 3-25)
++ //TODO PRER (PXA255: 3-26)
++ //TODO PFER (PXA255: 3-27)
++ //TODO PSSR (PXA255: 3-29)
++ //TODO PGSR0..PGSR2 (PXA255: 3-32)
++#endif
++
++#ifdef CONFIG_APM
++ apm_register_get_power_status(ramses_get_power_status);
++#endif
++
++ PCFR = PCFR_OPDE | PCFR_FS | PCFR_FP; // PXA255: 3-24
++
++ pm_power_off = ramses_shut_off;
++
++ return 0;
++}
++
++__initcall(ramses_init);
++
++
++
++/*
++ * ramses_init()
++ * Using PXA255 frequency points.
++ * Registering CPU frequency change support.
++ * CPU clock: 398.131 MHz (99.000-400.000 MHz)
++ * Starting kswapd
++ * devfs: v1.12a (20020514) Richard Gooch (rgooch@atnf.csiro.au)
++ * devfs: boot_options: 0x1
++ * pty: 256 Unix98 ptys configured
++ * pxa & ti16c754b serial driver
++ * tts/0 at irq 14 is a PXA UART
++ * tts/1 at irq 13 is a PXA UART
++ * tts/2 at irq 12 is a PXA UART
++ * tts/3 at irq 45 is a TI16750
++ * tts/4 at irq 46 is a TI16750
++ * tts/5 at irq 47 is a TI16750
++ * tts/6 at irq 48 is a TI16750
++ * LAN91C111: You shouldn't use auto-probing with insmod!
++ * SMSC LAN91C111 Driver (v2.2), (Linux Kernel 2.4 + Support for Odd Byte) ...
++ * eth0: SMC91C11xFD(rev:1) at 0xf0100300 IRQ:26 MEMSIZE ...
++ * ac97_codec: AC97 Audio codec, id: 0x5053:0x4304 (Philips UCB1400)
++ * NET4: Linux TCP/IP 1.0 for NET4.0
++ * IP Protocols: ICMP, UDP, TCP
++ * IP: routing cache hash table of 512 buckets, 4Kbytes
++ * TCP: Hash tables configured (established 4096 bind 4096)
++ * IP-Config: ...
++ * NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
++ * NetWinder Floating Point Emulator V0.95 (c) 1998-1999 Rebel.com
++ * Looking up port of RPC 100003/2 on 192.168.233.66
++ * Looking up port of RPC 100005/1 on 192.168.233.66
++ * VFS: Mounted root (nfs filesystem).
++ * Mounted devfs on /dev
++ * Freeing init memory: 68K
++ * INIT: version 2.84 booting
++ */
++
++
++
++MACHINE_START(RAMSES, "Ramses")
++ MAINTAINER("M&N Logistik-Lösungen Online GmbH")
++ BOOT_MEM(0xa0000000, 0x40000000, 0xfc000000)
++ BOOT_PARAMS(0xa0000100)
++ FIXUP(fixup_ramses)
++ MAPIO(ramses_map_io)
++ INITIRQ(ramses_init_irq)
++MACHINE_END
++
++EXPORT_SYMBOL(ramses_lcd_type);
++EXPORT_SYMBOL(ramses_lcd_power_on);
++EXPORT_SYMBOL(ramses_lcd_power_off);
++EXPORT_SYMBOL(ramses_lcd_backlight_on);
++EXPORT_SYMBOL(ramses_lcd_backlight_off);
++EXPORT_SYMBOL(ramses_lcd_set_intensity);
++EXPORT_SYMBOL(ramses_lcd_set_brightness);
++EXPORT_SYMBOL(ramses_lcd_set_contrast);
++EXPORT_SYMBOL(ramses_lcd_get_intensity);
++EXPORT_SYMBOL(ramses_lcd_get_brightness);
++EXPORT_SYMBOL(ramses_lcd_get_contrast);
++EXPORT_SYMBOL(ramses_hdq_get_reg);
++EXPORT_SYMBOL(ramses_set_corevolt);
++EXPORT_SYMBOL(ramses_corevolt_shadow);
+--- linux-2.4.21/arch/arm/mach-pxa/usb-char.c~pxa-usb
++++ linux-2.4.21/arch/arm/mach-pxa/usb-char.c
+@@ -211,7 +211,6 @@
+ 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;
+@@ -220,6 +219,7 @@
+
+ if ( machine_is_extenex1() ) {
+ #ifdef CONFIG_SA1100_EXTENEX1
++ string_desc_t * pString;
+ pDesc->dev.idVendor = make_word_c( 0xC9F );
+ pDesc->dev.idProduct = 1;
+ pDesc->dev.bcdDevice = make_word_c( 0x0001 );
+--- linux-2.4.21/arch/arm/mach-pxa/usb-eth.c~pxa-usbeth
++++ linux-2.4.21/arch/arm/mach-pxa/usb-eth.c
+@@ -52,6 +52,7 @@
+
+ #define ETHERNET_VENDOR_ID 0x49f
+ #define ETHERNET_PRODUCT_ID 0x505A
++#define ETHERNET_DEVICE_ID 0x0200
+ #define MAX_PACKET 32768
+ #define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+@@ -329,6 +330,7 @@
+ pd->b.ep2.wMaxPacketSize = make_word( usb_wsize );
+ pd->dev.idVendor = ETHERNET_VENDOR_ID;
+ pd->dev.idProduct = ETHERNET_PRODUCT_ID;
++ pd->dev.bcdDevice = ETHERNET_DEVICE_ID;
+ pstr = pxa_usb_kmalloc_string_descriptor( "PXA USB NIC" );
+ if ( pstr ) {
+ pxa_usb_set_string_descriptor( 1, pstr );
+--- linux-2.4.21/drivers/char/Config.in~i2c-ds1337
++++ linux-2.4.21/drivers/char/Config.in
+@@ -164,6 +164,7 @@
+
+ if [ "$CONFIG_I2C" != "n" ]; then
+ dep_tristate ' DS1307 RTC' CONFIG_I2C_DS1307 $CONFIG_I2C
++ dep_tristate ' DS1337 RTC' CONFIG_I2C_DS1337 $CONFIG_I2C
+ fi
+
+ source drivers/l3/Config.in
+--- linux-2.4.21/drivers/char/Makefile~i2c-ds1337
++++ linux-2.4.21/drivers/char/Makefile
+@@ -21,10 +21,11 @@
+ # All of the (potential) objects that export symbols.
+ # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
+
+-export-objs := busmouse.o console.o keyboard.o sysrq.o \
++export-objs := vt.o busmouse.o console.o keyboard.o sysrq.o \
+ misc.o pty.o random.o selection.o serial.o \
+ sonypi.o tty_io.o tty_ioctl.o generic_serial.o \
+- au1000_gpio.o hp_psaux.o nvram.o scx200.o
++ au1000_gpio.o hp_psaux.o nvram.o scx200.o \
++ input_keyb.o
+
+ mod-subdirs := joystick ftape drm drm-4.0 pcmcia
+
+@@ -129,6 +130,11 @@
+ ifeq ($(CONFIG_SA1100_CERF_CPLD),y)
+ KEYBD += cerf_keyb.o
+ endif
++ ifeq ($(CONFIG_ARCH_RAMSES),y)
++ KEYMAP = german.o
++ KEYBD += input_keyb.o
++ obj-m += sysctl.o
++ endif
+ ifeq ($(CONFIG_ARCH_FORTUNET),y)
+ KEYMAP := defkeymap.o
+ endif
+@@ -337,6 +343,7 @@
+
+ # I2C char devices
+ obj-$(CONFIG_I2C_DS1307) += ds1307.o
++obj-$(CONFIG_I2C_DS1337) += ds1337.o
+
+ subdir-$(CONFIG_MWAVE) += mwave
+ ifeq ($(CONFIG_MWAVE),y)
+@@ -372,4 +379,7 @@
+ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+
+ qtronixmap.c: qtronixmap.map
++ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
++
++german.c: german.map
+ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+--- linux-2.4.21/drivers/char/console.c~keyb-module
++++ linux-2.4.21/drivers/char/console.c
+@@ -150,7 +150,7 @@
+ static int con_open(struct tty_struct *, struct file *);
+ static void vc_init(unsigned int console, unsigned int rows,
+ unsigned int cols, int do_clear);
+-static void blank_screen(unsigned long dummy);
++//static void blank_screen(unsigned long dummy);
+ static void gotoxy(int currcons, int new_x, int new_y);
+ static void save_cur(int currcons);
+ static void reset_terminal(int currcons, int do_clear);
+@@ -158,7 +158,7 @@
+ static void set_vesa_blanking(unsigned long arg);
+ static void set_cursor(int currcons);
+ static void hide_cursor(int currcons);
+-static void unblank_screen_t(unsigned long dummy);
++//static void unblank_screen_t(unsigned long dummy);
+ static void console_callback(void *ignored);
+
+ static int printable; /* Is console ready for printing? */
+@@ -167,7 +167,7 @@
+ int console_blanked;
+
+ static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
+-static int blankinterval = 10*60*HZ;
++//static int blankinterval = 10*60*HZ;
+ static int vesa_off_interval;
+
+ static struct tq_struct console_callback_tq = {
+@@ -209,9 +209,9 @@
+ * Hook so that the power management routines can (un)blank
+ * the console on our behalf.
+ */
+-int (*console_blank_hook)(int);
++//int (*console_blank_hook)(int);
+
+-static struct timer_list console_timer;
++//static struct timer_list console_timer;
+
+ /*
+ * Low-Level Functions
+@@ -543,7 +543,7 @@
+
+ static void set_cursor(int currcons)
+ {
+- if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
++ if (!IS_FG || vcmode == KD_GRAPHICS)
+ return;
+ if (deccm) {
+ if (currcons == sel_cons)
+@@ -1287,7 +1287,7 @@
+ update_attr(currcons);
+ break;
+ case 9: /* set blanking interval */
+- blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
++ //blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
+ poke_blanked_console();
+ break;
+ case 10: /* set bell frequency in Hz */
+@@ -2575,11 +2575,11 @@
+ if (tty_register_driver(&console_driver))
+ panic("Couldn't register console driver\n");
+
+- init_timer(&console_timer);
+- console_timer.function = blank_screen;
+- if (blankinterval) {
+- mod_timer(&console_timer, jiffies + blankinterval);
+- }
++ //init_timer(&console_timer);
++ //console_timer.function = blank_screen;
++ //if (blankinterval) {
++ // mod_timer(&console_timer, jiffies + blankinterval);
++ //}
+
+ /*
+ * kmalloc is not running yet - we use the bootmem allocator.
+@@ -2744,11 +2744,12 @@
+ */
+ static void vesa_powerdown_screen(unsigned long dummy)
+ {
+- console_timer.function = unblank_screen_t;
++ //console_timer.function = unblank_screen_t;
+
+ vesa_powerdown();
+ }
+
++#if 0
+ static void timer_do_blank_screen(int entering_gfx, int from_timer_handler)
+ {
+ int currcons = fg_console;
+@@ -2797,12 +2798,14 @@
+ if (vesa_blank_mode)
+ sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1);
+ }
++#endif
+
+ void do_blank_screen(int entering_gfx)
+ {
+- timer_do_blank_screen(entering_gfx, 0);
++ //timer_do_blank_screen(entering_gfx, 0);
+ }
+
++#if 0
+ /*
+ * This is a timer handler
+ */
+@@ -2810,12 +2813,14 @@
+ {
+ unblank_screen();
+ }
++#endif
+
+ /*
+ * Called by timer as well as from vt_console_driver
+ */
+ void unblank_screen(void)
+ {
++#if 0
+ int currcons;
+
+ if (!console_blanked)
+@@ -2842,6 +2847,7 @@
+ /* Low-level driver cannot restore -> do it ourselves */
+ update_screen(fg_console);
+ set_cursor(fg_console);
++#endif
+ }
+
+ /*
+@@ -2849,11 +2855,12 @@
+ */
+ static void blank_screen(unsigned long dummy)
+ {
+- timer_do_blank_screen(0, 1);
++ //timer_do_blank_screen(0, 1);
+ }
+
+ void poke_blanked_console(void)
+ {
++#if 0
+ del_timer(&console_timer);
+ if (!vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+ return;
+@@ -2863,6 +2870,7 @@
+ } else if (blankinterval) {
+ mod_timer(&console_timer, jiffies + blankinterval);
+ }
++#endif
+ }
+
+ /*
+@@ -3088,7 +3096,7 @@
+ unblank_screen();
+ break;
+ case PM_SUSPEND:
+- do_blank_screen(0);
++ //do_blank_screen(0);
+ break;
+ }
+ return 0;
+@@ -3106,7 +3114,8 @@
+ EXPORT_SYMBOL(video_scan_lines);
+ EXPORT_SYMBOL(vc_resize);
+ EXPORT_SYMBOL(fg_console);
+-EXPORT_SYMBOL(console_blank_hook);
++//EXPORT_SYMBOL(console_blank_hook);
++EXPORT_SYMBOL(console_driver);
+ #ifdef CONFIG_VT
+ EXPORT_SYMBOL(vt_cons);
+ #endif
+--- /dev/null
++++ linux-2.4.21/drivers/char/ds1337.c
+@@ -0,0 +1,545 @@
++/*
++ * ds1337.c
++ *
++ * Device driver for Dallas Semiconductor's Real Time Controller DS1337.
++ *
++ * Copyright (C) 2003 M&N Logistik-Lösungen Online GmbH
++ *
++ * 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.
++ *
++ * Documentation for this Chip: http://pdfserv.maxim-ic.com/arpdf/DS1337.pdf
++ */
++
++#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 "ds1337.h"
++
++//#define DEBUG 1
++
++#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 = DS1337_I2C_SLAVE_ADDR;
++struct i2c_driver ds1337_driver;
++struct i2c_client *ds1337_i2c_client = 0;
++static spinlock_t ds1337_rtc_lock = SPIN_LOCK_UNLOCKED;
++
++static unsigned short ignore[] = { I2C_CLIENT_END };
++static unsigned short normal_addr[] = { DS1337_I2C_SLAVE_ADDR, I2C_CLIENT_END };
++
++static int ds1337_rtc_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
++static int ds1337_rtc_noop(struct inode *inode, struct file *file);
++
++static int ds1337_probe(struct i2c_adapter *adap);
++static int ds1337_detach(struct i2c_client *client);
++static int ds1337_command(struct i2c_client *client, unsigned int cmd, void *arg);
++
++
++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 struct file_operations rtc_fops = {
++ .owner = THIS_MODULE,
++ .ioctl = ds1337_rtc_ioctl,
++ .open = ds1337_rtc_noop,
++ .release = ds1337_rtc_noop,
++};
++
++static struct miscdevice ds1337_rtc_miscdev = {
++ RTC_MINOR,
++ "rtc",
++ &rtc_fops
++};
++
++
++struct i2c_driver ds1337_driver = {
++ .name = "DS1337",
++ .id = I2C_DRIVERID_DS1337,
++ .flags = I2C_DF_NOTIFY,
++ .attach_adapter = ds1337_probe,
++ .detach_client = ds1337_detach,
++ .command = ds1337_command
++};
++
++#define DAT(x) ((unsigned int)((x)->data)) /* keep the control register info */
++
++
++static int ds1337_readram(char *buf, int len)
++{
++ unsigned long flags;
++ unsigned char ad[1] = { 0 };
++ int ret;
++ struct i2c_msg msgs[2] = {
++ {ds1337_i2c_client->addr, 0, 1, ad},
++ {ds1337_i2c_client->addr, I2C_M_RD, len, buf}
++ };
++
++ spin_lock_irqsave(&ds1337_rtc_lock, flags);
++ ret = i2c_transfer(ds1337_i2c_client->adapter, msgs, 2);
++ spin_unlock_irqrestore(&ds1337_rtc_lock, flags);
++
++ return ret;
++}
++
++
++static void ds1337_setreg(struct i2c_client *c, unsigned char reg, unsigned char val)
++{
++ unsigned char buf[2];
++ buf[0] = reg;
++ buf[1] = val;
++ i2c_master_send(c, (char *) buf, 2);
++}
++
++static int ds1337_attach(struct i2c_adapter *adap, int addr,
++ unsigned short flags, int kind)
++{
++ struct i2c_client *c;
++ unsigned char buf[DS1337_MEM_SIZE], ad[1] = { 7 };
++ struct i2c_msg msgs[2] = {
++ {addr, 0, 1, ad},
++ {addr, I2C_M_RD, 1, buf}
++ };
++ int ret;
++
++ if (rtc_debug>1)
++ printk("%s(adap,%d,%d,%d)\n", __FUNCTION__, addr, flags, kind);
++
++ c = (struct i2c_client *) kmalloc(sizeof(*c), GFP_KERNEL);
++ if (!c)
++ return -ENOMEM;
++
++ strcpy(c->name, "DS1337");
++ c->id = ds1337_driver.id;
++ c->flags = 0;
++ c->addr = addr;
++ c->adapter = adap;
++ c->driver = &ds1337_driver;
++ c->data = NULL;
++
++ ret = i2c_transfer(c->adapter, msgs, 2);
++
++ if (ret == 2) {
++ DAT(c) = buf[0];
++ } else
++ printk("ds1337_attach(): i2c_transfer() returned %d.\n", ret);
++
++ ds1337_i2c_client = c;
++
++ ds1337_readram(buf, DS1337_MEM_SIZE);
++
++ // set 24 hour mode
++ ds1337_setreg(c, 0x2, buf[2] | DS1337_HOUR24);
++ // INTCN sets INTB to alarm2 (disables SQW)
++ ds1337_setreg(c, 0x5, buf[5] & 0x7f); // clear century
++ ds1337_setreg(c, 0x7, 0x00); // clear Alarm 1 seconds
++ ds1337_setreg(c, 0x8, 0x00); // clear Alarm 1 minutes
++ ds1337_setreg(c, 0x9, 0x40); // clear Alarm 1 hours, 24 hour on
++ ds1337_setreg(c, 0xA, 0x00); // clear Alarm 1 date
++ ds1337_setreg(c, 0xB, 0x00); // clear Alarm 2 minutes
++ ds1337_setreg(c, 0xC, 0x40); // clear Alarm 2 hours, 24 hour on
++ ds1337_setreg(c, 0xD, 0x00); // clear Alarm 2 date
++ ds1337_setreg(c, 0xe, 4); // nEOSC enabled
++ ds1337_setreg(c, 0xf, 0); // clear OSF, A2F, A1F
++
++ return i2c_attach_client(c);
++}
++
++
++static int ds1337_probe(struct i2c_adapter *adap)
++{
++ if (rtc_debug>1)
++ printk("%s()\n", __FUNCTION__);
++
++ return i2c_probe(adap, &addr_data, ds1337_attach);
++}
++
++
++static int ds1337_detach(struct i2c_client *client)
++{
++ if (rtc_debug>1)
++ printk("%s()\n", __FUNCTION__);
++
++ i2c_detach_client(client);
++
++ return 0;
++}
++
++
++static void ds1337_convert_to_time(struct rtc_time *dt, char *buf)
++{
++ if (rtc_debug>1)
++ printk("%s()\n", __FUNCTION__);
++
++ dt->tm_sec = BCD_TO_BIN(buf[0]);
++ dt->tm_min = BCD_TO_BIN(buf[1]);
++ dt->tm_hour = DS1337_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("ds1337_get_datetime: year = %d\n", dt->tm_year);
++ printk("ds1337_get_datetime: mon = %d\n", dt->tm_mon);
++ printk("ds1337_get_datetime: mday = %d\n", dt->tm_mday);
++ printk("ds1337_get_datetime: hour = %d\n", dt->tm_hour);
++ printk("ds1337_get_datetime: min = %d\n", dt->tm_min);
++ printk("ds1337_get_datetime: sec = %d\n", dt->tm_sec);
++ }
++}
++
++
++static int ds1337_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;
++
++ if (rtc_debug)
++ printk("%s()\n", __FUNCTION__);
++
++ memset(buf, 0, sizeof(buf));
++
++ ret = i2c_transfer(client->adapter, msgs, 2);
++
++ if (ret == 2) {
++ ds1337_convert_to_time(dt, buf);
++ ret = 0;
++ } else
++ printk("ds1337_get_datetime(), i2c_transfer() returned %d\n", ret);
++
++ return ret;
++}
++
++
++static int ds1337_set_datetime(struct i2c_client *client,
++ struct rtc_time *dt, int datetoo)
++{
++ unsigned char buf[8];
++ int ret, len = 4;
++
++ if (rtc_debug)
++ printk("%s()\n", __FUNCTION__);
++
++ if (rtc_debug > 2) {
++ printk("ds1337_set_datetime: tm_year = %d\n", dt->tm_year);
++ printk("ds1337_set_datetime: tm_mon = %d\n", dt->tm_mon);
++ printk("ds1337_set_datetime: tm_mday = %d\n", dt->tm_mday);
++ printk("ds1337_set_datetime: tm_hour = %d\n", dt->tm_hour);
++ printk("ds1337_set_datetime: tm_min = %d\n", dt->tm_min);
++ printk("ds1337_set_datetime: tm_sec = %d\n", dt->tm_sec);
++ }
++
++ buf[0] = 0; /* register address on DS1337 */
++ buf[1] = (BIN_TO_BCD(dt->tm_sec));
++ buf[2] = (BIN_TO_BCD(dt->tm_min));
++ buf[3] = (BIN_TO_BCD(dt->tm_hour)) | DS1337_HOUR24;
++
++ 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("ds1337_set_datetime(), i2c_master_send() returned %d\n",
++ ret);
++
++
++ return ret;
++}
++
++
++#if 0
++static int ds1337_get_ctrl(struct i2c_client *client, unsigned char *ctrl)
++{
++ *ctrl = DAT(client);
++
++ if (rtc_debug)
++ printk("%s():%d\n", __FUNCTION__, *ctrl);
++
++ return 0;
++}
++
++
++static int ds1337_set_ctrl(struct i2c_client *client, unsigned char *cinfo)
++{
++ unsigned char buf[2];
++ int ret;
++
++ if (rtc_debug)
++ printk("%s(%d)\n", __FUNCTION__, *cinfo);
++
++ buf[0] = 7; /* control register address on DS1337 */
++ 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;
++}
++#endif
++
++
++static int ds1337_command(struct i2c_client *client, unsigned int cmd,
++ void *arg)
++{
++ if (rtc_debug)
++ printk("%s(client,,%u,arg)\n", __FUNCTION__, cmd);
++
++ switch (cmd) {
++ case DS1337_GETDATETIME:
++ return ds1337_get_datetime(client, arg);
++
++ case DS1337_SETTIME:
++ return ds1337_set_datetime(client, arg, 0);
++
++ case DS1337_SETDATETIME:
++ return ds1337_set_datetime(client, arg, 1);
++
++ default:
++ return -EINVAL;
++ }
++}
++
++
++static int ds1337_rtc_noop(struct inode *inode, struct file *file)
++{
++ return 0;
++}
++
++
++static int ds1337_rtc_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ unsigned long flags;
++ struct rtc_time wtime;
++ int status = 0;
++
++ if (rtc_debug)
++ printk("%s()\n", __FUNCTION__);
++
++ switch (cmd) {
++ default:
++ case RTC_UIE_ON: // mask ints from RTC updates
++ case RTC_UIE_OFF:
++ case RTC_PIE_ON: // allow periodic interrupts
++ case RTC_PIE_OFF:
++ case RTC_AIE_ON: // mask alarm int enable bit
++ case RTC_AIE_OFF:
++ case RTC_ALM_SET:
++ /*
++ * This expects a struct rtc_time. Writing 0xff means
++ * "don't care" or "match all". Only the tm_hour,
++ * tm_min and tm_sec are used.
++ */
++ case RTC_ALM_READ:
++ // get_rtc_alm_time(&wtime);
++ case RTC_IRQP_READ: // Read the periodic IRQ rate
++ case RTC_IRQP_SET: // Set periodic IRQ rate
++ case RTC_EPOCH_READ:
++ // return put_user (epoch, (unsigned long *)arg);
++ case RTC_EPOCH_SET:
++ case RTC_WKALM_SET:
++ case RTC_WKALM_RD:
++ status = -EINVAL;
++ break;
++
++ case RTC_RD_TIME:
++ spin_lock_irqsave(&ds1337_rtc_lock, flags);
++ ds1337_command(ds1337_i2c_client, DS1337_GETDATETIME, &wtime);
++ spin_unlock_irqrestore(&ds1337_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(&ds1337_rtc_lock, flags);
++ ds1337_command(ds1337_i2c_client, DS1337_SETDATETIME, &wtime);
++ spin_unlock_irqrestore(&ds1337_rtc_lock, flags);
++ break;
++ }
++
++ return status;
++}
++
++
++static char *ds1337_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 ds1337_rtc_proc_output(char *buf)
++{
++#define CHECK(ctrl,bit) ((ctrl & bit) ? "yes" : "no")
++
++ unsigned char ram[DS1337_MEM_SIZE];
++ int ret;
++
++ char *p = buf;
++
++ ret = ds1337_readram(ram, DS1337_MEM_SIZE);
++ if (ret > 0) {
++#ifdef DEBUG
++ int i;
++ char text[9];
++#endif
++ struct rtc_time dt;
++
++ p += sprintf(p, "DS1337 (i2c Serial Real Time Clock)\n");
++
++ ds1337_convert_to_time(&dt, ram);
++ p += sprintf(p, "Date/Time: %02d-%s-%04d %02d:%02d:%02d\n",
++ dt.tm_mday, ds1337_mon2str(dt.tm_mon),
++ dt.tm_year + 1900, dt.tm_hour, dt.tm_min, dt.tm_sec);
++
++#ifdef DEBUG
++ p += sprintf(p, "RAM dump:\n");
++ text[8] = '\0';
++ for (i = 0; i < DS1337_MEM_SIZE; i++) {
++ if ((i % 8) == 0)
++ p += sprintf(p, "%02X: ", 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");
++#endif
++ } else {
++ p += sprintf(p, "Failed to read RTC memory!\n");
++ }
++
++ return p - buf;
++}
++
++
++static int ds1337_rtc_read_proc(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len = ds1337_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 ds1337_init(void)
++{
++ int retval = 0;
++
++ if (rtc_debug>1)
++ printk("%s()\n", __FUNCTION__);
++
++ if (slave_address != 0xffff) {
++ normal_addr[0] = slave_address;
++ }
++
++ if (normal_addr[0] == 0xffff) {
++ printk(KERN_ERR
++ "I2C: Invalid slave address for DS1337 RTC (%#x)\n",
++ normal_addr[0]);
++ return -EINVAL;
++ }
++
++ retval = i2c_add_driver(&ds1337_driver);
++
++ if (retval == 0) {
++ misc_register(&ds1337_rtc_miscdev);
++ create_proc_read_entry(DS1337_PROC_NAME, 0, 0,
++ ds1337_rtc_read_proc, NULL);
++ printk("I2C: DS1337 RTC driver loaded\n");
++ }
++ return retval;
++}
++
++
++static __exit void ds1337_exit(void)
++{
++ if (rtc_debug>1)
++ printk("%s()\n", __FUNCTION__);
++
++ remove_proc_entry(DS1337_PROC_NAME, NULL);
++ misc_deregister(&ds1337_rtc_miscdev);
++ i2c_del_driver(&ds1337_driver);
++}
++
++
++module_init(ds1337_init);
++module_exit(ds1337_exit);
++
++MODULE_PARM(slave_address, "i");
++MODULE_PARM_DESC(slave_address, "I2C slave address for DS1337 RTC");
++
++MODULE_AUTHOR("M&N Logistik-Lösungen Online GmbH");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ linux-2.4.21/drivers/char/ds1337.h
+@@ -0,0 +1,43 @@
++/*
++ * ds1337.h
++ *
++ * Copyright (C) 2003 M&N Logistik-Lösungen Online GmbH
++ *
++ * 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 DS1337_H
++#define DS1337_H
++
++#define DS1337_I2C_SLAVE_ADDR 0x68
++//#define DS1337_RAM_ADDR_START 0x10
++//#define DS1337_RAM_ADDR_END 0x10
++#define DS1337_MEM_SIZE 0x10
++
++#define DS1337_PROC_NAME "driver/ds1337"
++
++struct rtc_mem {
++ unsigned int loc;
++ unsigned int nr;
++ unsigned char *data;
++};
++
++#define DS1337_GETDATETIME 0
++#define DS1337_SETTIME 1
++#define DS1337_SETDATETIME 2
++
++#define DS1337_RATE_1HZ 0x00 /* Rate Select 1 Hz */
++#define DS1337_RATE_4096HZ 0x01 /* Rate Select 4096 kHz */
++#define DS1337_RATE_8192HZ 0x02 /* Rate Select 8192 kHz */
++#define DS1337_RATE_32768HZ 0x03 /* Rate Select 32768 kHz */
++
++#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
++#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
++
++#define DS1337_HOUR12 0x40
++#define DS1337_HOUR24 0x00
++#define DS1337_HOURS_24(val) BCD_TO_BIN((val & 0x3f))
++
++#endif
+--- /dev/null
++++ linux-2.4.21/drivers/char/german.map
+@@ -0,0 +1,528 @@
++keymaps 0-2,4-6,8-10,12
++keycode 1 = Escape Escape
++ alt keycode 1 = Meta_Escape
++ shift alt keycode 1 = Meta_Escape
++keycode 2 = one exclam
++ alt keycode 2 = Meta_one
++ shift alt keycode 2 = Meta_exclam
++keycode 3 = two quotedbl twosuperior nul
++ alt keycode 3 = Meta_two
++ shift alt keycode 3 = Meta_quotedbl
++ control alt keycode 3 = Meta_nul
++keycode 4 = three section threesuperior Escape
++ alt keycode 4 = Meta_three
++ control alt keycode 4 = Meta_Escape
++keycode 5 = four dollar
++ alt keycode 5 = Meta_four
++ shift alt keycode 5 = Meta_dollar
++keycode 6 = five percent
++ alt keycode 6 = Meta_five
++ shift alt keycode 6 = Meta_percent
++keycode 7 = six ampersand
++ control keycode 7 = Control_asciicircum
++ alt keycode 7 = Meta_six
++ shift alt keycode 7 = Meta_ampersand
++keycode 8 = seven slash braceleft
++ alt keycode 8 = Meta_seven
++ shift alt keycode 8 = Meta_slash
++ altgr alt keycode 8 = Meta_braceleft
++keycode 9 = eight parenleft bracketleft
++ alt keycode 9 = Meta_eight
++ shift alt keycode 9 = Meta_parenleft
++ altgr alt keycode 9 = Meta_bracketleft
++keycode 10 = nine parenright bracketright
++ altgr control keycode 10 = Control_bracketright
++ alt keycode 10 = Meta_nine
++ shift alt keycode 10 = Meta_parenright
++ altgr alt keycode 10 = Meta_bracketright
++keycode 11 = zero equal braceright
++ alt keycode 11 = Meta_zero
++ shift alt keycode 11 = Meta_equal
++ altgr alt keycode 11 = Meta_braceright
++keycode 12 = ssharp question backslash
++ altgr control keycode 12 = Control_backslash
++ shift alt keycode 12 = Meta_question
++ altgr alt keycode 12 = Meta_backslash
++keycode 13 = apostrophe grave
++ alt keycode 13 = 0x08b4
++ shift alt keycode 13 = Meta_grave
++keycode 14 = BackSpace Delete
++ alt keycode 14 = Meta_BackSpace
++ shift alt keycode 14 = Meta_Delete
++keycode 15 = Tab Tab
++ alt keycode 15 = Meta_Tab
++ shift alt keycode 15 = Meta_Tab
++keycode 16 = +q +Q at Control_q Control_q Control_q Meta_q Meta_Q Meta_at Meta_Control_q
++keycode 17 = w
++keycode 18 = +e +E currency Control_e Control_e Control_e Meta_e Meta_E Meta_e Meta_Control_e
++keycode 19 = r
++keycode 20 = t
++keycode 21 = z
++keycode 22 = u
++keycode 23 = i
++keycode 24 = o
++keycode 25 = p
++keycode 26 = +udiaeresis +Udiaeresis
++keycode 27 = plus asterisk asciitilde
++ alt keycode 27 = Meta_plus
++ shift alt keycode 27 = Meta_asterisk
++keycode 28 = Return
++ alt keycode 28 = Meta_Control_m
++keycode 29 = Control
++keycode 30 = a
++keycode 31 = s
++keycode 32 = d
++keycode 33 = f
++keycode 34 = g
++keycode 35 = h
++keycode 36 = j
++keycode 37 = k
++keycode 38 = l
++keycode 39 = +odiaeresis +Odiaeresis
++keycode 40 = +adiaeresis +Adiaeresis
++keycode 41 = asciicircum degree Meta_asciicircum Control_asciicircum
++ control alt keycode 41 = Meta_Control_asciicircum
++keycode 42 = Shift
++keycode 43 = numbersign apostrophe
++ alt keycode 43 = Meta_numbersign
++ shift alt keycode 43 = Meta_apostrophe
++keycode 44 = y
++keycode 45 = x
++keycode 46 = c
++keycode 47 = v
++keycode 48 = b
++keycode 49 = n
++keycode 50 = +m +M mu Control_m Control_m Control_m Meta_m Meta_M Meta_m Meta_Control_m
++keycode 51 = comma semicolon
++ alt keycode 51 = Meta_comma
++ shift alt keycode 51 = Meta_semicolon
++keycode 52 = period colon
++ alt keycode 52 = Meta_period
++ shift alt keycode 52 = Meta_colon
++keycode 53 = minus underscore Meta_minus
++ shift control keycode 53 = Control_underscore
++ alt keycode 53 = Meta_minus
++ shift alt keycode 53 = Meta_underscore
++keycode 54 = Shift
++keycode 55 = KP_Multiply
++ altgr keycode 55 = Hex_C
++keycode 56 = Alt
++keycode 57 = space space Meta_space nul
++ alt keycode 57 = Meta_space
++ shift alt keycode 57 = Meta_space
++ control alt keycode 57 = Meta_nul
++keycode 58 = Caps_Lock
++keycode 59 = F1 F13 Console_13 F25
++ altgr control keycode 59 = F1
++ alt keycode 59 = Console_1
++ control alt keycode 59 = Console_1
++keycode 60 = F2 F14 Console_14 F26
++ altgr control keycode 60 = F2
++ alt keycode 60 = Console_2
++ control alt keycode 60 = Console_2
++keycode 61 = F3 F15 Console_15 F27
++ altgr control keycode 61 = F3
++ alt keycode 61 = Console_3
++ control alt keycode 61 = Console_3
++keycode 62 = F4 F16 Console_16 F28
++ altgr control keycode 62 = F4
++ alt keycode 62 = Console_4
++ control alt keycode 62 = Console_4
++keycode 63 = F5 F17 Console_17 F29
++ altgr control keycode 63 = F5
++ alt keycode 63 = Console_5
++ control alt keycode 63 = Console_5
++keycode 64 = F6 F18 Console_18 F30
++ altgr control keycode 64 = F6
++ alt keycode 64 = Console_6
++ control alt keycode 64 = Console_6
++keycode 65 = F7 F19 Console_19 F31
++ altgr control keycode 65 = F7
++ alt keycode 65 = Console_7
++ control alt keycode 65 = Console_7
++keycode 66 = F8 F20 Console_20 F32
++ altgr control keycode 66 = F8
++ alt keycode 66 = Console_8
++ control alt keycode 66 = Console_8
++keycode 67 = F9 F21 Console_21 F33
++ altgr control keycode 67 = F9
++ alt keycode 67 = Console_9
++ control alt keycode 67 = Console_9
++keycode 68 = F10 F22 Console_22 F34
++ altgr control keycode 68 = F10
++ alt keycode 68 = Console_10
++ control alt keycode 68 = Console_10
++keycode 69 = Num_Lock
++ altgr keycode 69 = Hex_A
++keycode 70 = Scroll_Lock Show_Memory Show_Registers Show_State
++ alt keycode 70 = Scroll_Lock
++keycode 71 = KP_7
++ altgr keycode 71 = Hex_7
++ alt keycode 71 = Ascii_7
++keycode 72 = KP_8
++ altgr keycode 72 = Hex_8
++ alt keycode 72 = Ascii_8
++keycode 73 = KP_9
++ altgr keycode 73 = Hex_9
++ alt keycode 73 = Ascii_9
++keycode 74 = KP_Subtract
++ altgr keycode 74 = Hex_D
++keycode 75 = KP_4
++ altgr keycode 75 = Hex_4
++ alt keycode 75 = Ascii_4
++keycode 76 = KP_5
++ altgr keycode 76 = Hex_5
++ alt keycode 76 = Ascii_5
++keycode 77 = KP_6
++ altgr keycode 77 = Hex_6
++ alt keycode 77 = Ascii_6
++keycode 78 = KP_Add
++ altgr keycode 78 = Hex_E
++keycode 79 = KP_1
++ altgr keycode 79 = Hex_1
++ alt keycode 79 = Ascii_1
++keycode 80 = KP_2
++ altgr keycode 80 = Hex_2
++ alt keycode 80 = Ascii_2
++keycode 81 = KP_3
++ altgr keycode 81 = Hex_3
++ alt keycode 81 = Ascii_3
++keycode 82 = KP_0
++ altgr keycode 82 = Hex_0
++ alt keycode 82 = Ascii_0
++keycode 83 = KP_Comma
++ 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
++ shift alt keycode 86 = Meta_greater
++ altgr alt keycode 86 = Meta_bar
++keycode 87 = F11 F23 Console_23 F35
++ altgr control keycode 87 = F11
++ alt keycode 87 = Console_11
++ control alt keycode 87 = Console_11
++keycode 88 = F12 F24 Console_24 F36
++ altgr control keycode 88 = F12
++ alt keycode 88 = Console_12
++ control alt keycode 88 = Console_12
++keycode 89 = slash question degree
++ alt keycode 89 = Meta_slash
++ shift alt keycode 89 = Meta_question
++keycode 90 =
++keycode 91 =
++keycode 92 =
++keycode 93 =
++keycode 94 =
++keycode 95 =
++keycode 96 = KP_Enter
++ altgr keycode 96 = Hex_F
++keycode 97 = Control
++keycode 98 = KP_Divide
++ altgr keycode 98 = Hex_B
++keycode 99 = Compose
++keycode 100 = AltGr
++ alt keycode 100 = Compose
++keycode 101 = Break
++keycode 102 = Find
++keycode 103 = Up
++ alt keycode 103 = KeyboardSignal
++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
++ shift alt keycode 112 = VoidSymbol
++ altgr alt keycode 112 = VoidSymbol
++keycode 113 = F13
++ shift alt keycode 113 = VoidSymbol
++ altgr alt keycode 113 = VoidSymbol
++keycode 114 = F14
++ shift alt keycode 114 = VoidSymbol
++ altgr alt keycode 114 = VoidSymbol
++keycode 115 = Help
++ shift alt keycode 115 = VoidSymbol
++ altgr alt keycode 115 = VoidSymbol
++keycode 116 = Do
++ shift alt keycode 116 = VoidSymbol
++ altgr alt keycode 116 = VoidSymbol
++keycode 117 = F17
++ shift alt keycode 117 = VoidSymbol
++ altgr alt keycode 117 = VoidSymbol
++keycode 118 = KP_MinPlus
++ shift alt keycode 118 = VoidSymbol
++ altgr alt keycode 118 = VoidSymbol
++keycode 119 = Pause
++keycode 120 =
++keycode 121 =
++keycode 122 =
++keycode 123 =
++keycode 124 =
++#keycode 125 = Decr_Console
++#keycode 126 = Incr_Console
++keycode 127 = Compose
++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 '!' '!' to '¡'
++compose '"' 'A' to 'Ä'
++compose '"' 'E' to 'Ë'
++compose '"' 'I' to 'Ï'
++compose '"' 'O' to 'Ö'
++compose '"' 'U' to 'Ü'
++compose '"' 'Y' to '¾'
++compose '"' 'a' to 'ä'
++compose '"' 'c' to '©'
++compose '"' 'e' to 'ë'
++compose '"' 'i' to 'ï'
++compose '"' 'o' to 'ö'
++compose '"' 'r' to '®'
++compose '"' 'u' to 'ü'
++compose '"' 'y' to 'ÿ'
++compose '(' 'c' to '©'
++compose '(' 'r' to '®'
++compose '+' '-' to '±'
++compose ',' 'A' to '¡'
++compose ',' 'C' to 'Ç'
++compose ',' 'E' to 'Ê'
++compose ',' 'G' to '«'
++compose ',' 'I' to 'Ç'
++compose ',' 'K' to 'Ó'
++compose ',' 'L' to '¦'
++compose ',' 'N' to 'Ñ'
++compose ',' 'R' to '£'
++compose ',' 'S' to 'ª'
++compose ',' 'T' to 'Þ'
++compose ',' 'U' to 'Ù'
++compose ',' 'a' to '±'
++compose ',' 'c' to 'ç'
++compose ',' 'e' to 'ê'
++compose ',' 'g' to '»'
++compose ',' 'i' to 'ç'
++compose ',' 'k' to 'ó'
++compose ',' 'l' to '¶'
++compose ',' 'n' to 'ñ'
++compose ',' 'r' to '³'
++compose ',' 's' to 'º'
++compose ',' 't' to 'þ'
++compose ',' 'u' to 'ù'
++compose '-' ':' to '÷'
++compose '-' 'A' to 'ª'
++compose '-' 'C' to '¢'
++compose '-' 'D' to 'Ð'
++compose '-' 'E' to '¤'
++compose '-' 'H' to '¡'
++compose '-' 'L' to '£'
++compose '-' 'O' to 'º'
++compose '-' 'T' to '¬'
++compose '-' 'Y' to '¥'
++compose '-' 'a' to 'ª'
++compose '-' 'c' to '¢'
++compose '-' 'd' to 'ð'
++compose '-' 'e' to '¤'
++compose '-' 'h' to '±'
++compose '-' 'l' to '£'
++compose '-' 'l' to '¥'
++compose '-' 'l' to '³'
++compose '-' 'o' to 'º'
++compose '-' 't' to '¼'
++compose '.' '.' to '·'
++compose '.' 'C' to 'Å'
++compose '.' 'C' to 'Õ'
++compose '.' 'E' to 'Ì'
++compose '.' 'I' to '©'
++compose '.' 'Z' to '¯'
++compose '.' 'c' to 'å'
++compose '.' 'c' to 'õ'
++compose '.' 'e' to 'ì'
++compose '.' 'i' to '¹'
++compose '.' 'z' to '¿'
++compose '/' 'D' to 'Ð'
++compose '/' 'L' to '£'
++compose '/' 'O' to 'Ø'
++compose '/' 'T' to '¬'
++compose '/' 'c' to '¢'
++compose '/' 'd' to 'ð'
++compose '/' 'l' to '³'
++compose '/' 'o' to 'ø'
++compose '/' 't' to '¼'
++compose '0' 'A' to 'Å'
++compose '0' 'U' to 'Ù'
++compose '0' 'a' to 'å'
++compose '0' 'u' to 'ù'
++compose '1' '2' to '½'
++compose '1' '4' to '¼'
++compose '3' '4' to '¾'
++compose ':' '-' to '÷'
++compose ':' 'A' to 'Ä'
++compose ':' 'E' to 'Ë'
++compose ':' 'O' to 'Ö'
++compose ':' 'U' to 'Ü'
++compose ':' 'a' to 'ä'
++compose ':' 'e' to 'ë'
++compose ':' 'o' to 'ö'
++compose ':' 'u' to 'ü'
++compose '<' '<' to '«'
++compose '>' '>' to '»'
++compose '?' '?' to '¿'
++compose 'A' 'A' to 'Å'
++compose 'A' 'E' to 'Æ'
++compose 'I' 'J' to '¾'
++compose 'L' '=' to '£'
++compose 'N' 'G' to '½'
++compose 'N' 'H' to 'Ñ'
++compose 'N' 'N' to 'Ñ'
++compose 'N' 'Y' to 'Ñ'
++compose 'N' 'h' to 'Ñ'
++compose 'N' 'n' to 'Ñ'
++compose 'N' 'y' to 'Ñ'
++compose 'O' 'A' to 'Å'
++compose 'O' 'E' to '¼'
++compose 'O' 'e' to '¼'
++compose 'T' 'H' to 'Þ'
++compose 'U' 'U' to 'Ù'
++compose 'Y' '=' to '¥'
++compose '\'' 'A' to 'Á'
++compose '\'' 'C' to 'Æ'
++compose '\'' 'E' to 'É'
++compose '\'' 'I' to 'Í'
++compose '\'' 'L' to 'Å'
++compose '\'' 'N' to 'Ñ'
++compose '\'' 'O' to 'Ó'
++compose '\'' 'R' to 'À'
++compose '\'' 'S' to '¦'
++compose '\'' 'U' to 'Ú'
++compose '\'' 'Y' to 'Ý'
++compose '\'' 'Z' to '¬'
++compose '\'' 'a' to 'á'
++compose '\'' 'c' to 'æ'
++compose '\'' 'e' to 'é'
++compose '\'' 'i' to 'í'
++compose '\'' 'l' to 'å'
++compose '\'' 'n' to 'ñ'
++compose '\'' 'o' to 'ó'
++compose '\'' 'r' to 'à'
++compose '\'' 's' to '¶'
++compose '\'' 'u' to 'ú'
++compose '\'' 'y' to 'ý'
++compose '\'' 'z' to '¼'
++compose '^' '!' to '¡'
++compose '^' '*' to '×'
++compose '^' '.' to '·'
++compose '^' '/' to '÷'
++compose '^' '1' to '¹'
++compose '^' '2' to '²'
++compose '^' '3' to '³'
++compose '^' ':' to '÷'
++compose '^' '?' to '¿'
++compose '^' 'A' to 'Â'
++compose '^' 'C' to 'Ç'
++compose '^' 'D' to 'Ð'
++compose '^' 'E' to 'Ê'
++compose '^' 'G' to 'Ô'
++compose '^' 'H' to '¦'
++compose '^' 'I' to 'Î'
++compose '^' 'J' to '¬'
++compose '^' 'L' to '¥'
++compose '^' 'N' to 'Ñ'
++compose '^' 'R' to 'Ø'
++compose '^' 'S' to '¦'
++compose '^' 'T' to '«'
++compose '^' 'U' to 'Û'
++compose '^' 'Z' to '´'
++compose '^' 'a' to 'â'
++compose '^' 'c' to 'ç'
++compose '^' 'd' to 'ð'
++compose '^' 'e' to 'ê'
++compose '^' 'g' to 'ø'
++compose '^' 'h' to '¶'
++compose '^' 'i' to 'î'
++compose '^' 'j' to '¼'
++compose '^' 'l' to 'µ'
++compose '^' 'n' to 'ñ'
++compose '^' 'o' to 'ô'
++compose '^' 'r' to 'ø'
++compose '^' 's' to '¨'
++compose '^' 't' to '»'
++compose '^' 'u' to 'û'
++compose '^' 'x' to '×'
++compose '^' 'z' to '¸'
++compose '`' 'A' to 'À'
++compose '`' 'E' to 'È'
++compose '`' 'I' to 'Ì'
++compose '`' 'O' to 'Ò'
++compose '`' 'U' to 'Ù'
++compose '`' 'a' to 'à'
++compose '`' 'e' to 'è'
++compose '`' 'i' to 'ì'
++compose '`' 'o' to 'ò'
++compose '`' 'u' to 'ù'
++compose 'a' 'a' to 'å'
++compose 'a' 'e' to 'æ'
++compose 'c' '/' to '¢'
++compose 'c' '=' to '¢'
++compose 'e' '=' to '¤'
++compose 'i' 'j' to 'ÿ'
++compose 'm' 'u' to 'µ'
++compose 'n' 'g' to '¿'
++compose 'n' 'h' to 'ñ'
++compose 'n' 'n' to 'ñ'
++compose 'o' 'a' to 'å'
++compose 'o' 'e' to '½'
++compose 's' 's' to 'ß'
++compose 's' 'z' to 'ß'
++compose 't' 'h' to 'þ'
++compose 'u' 'u' to 'ù'
++compose 'v' 'S' to '¦'
++compose 'v' 'Z' to '´'
++compose 'v' 's' to '¨'
++compose 'v' 'z' to '¸'
++compose 'x' 'x' to '×'
++compose '~' 'A' to 'Ã'
++compose '~' 'G' to '«'
++compose '~' 'I' to '¥'
++compose '~' 'N' to 'Ñ'
++compose '~' 'O' to 'Õ'
++compose '~' 'U' to 'Ý'
++compose '~' 'a' to 'ã'
++compose '~' 'g' to '»'
++compose '~' 'i' to 'µ'
++compose '~' 'n' to 'ñ'
++compose '~' 'o' to 'õ'
++compose '~' 'u' to 'ý'
+--- /dev/null
++++ linux-2.4.21/drivers/char/input_keyb.c
+@@ -0,0 +1,167 @@
++/*
++ * linux/drivers/char/input_keyb.c by Russ Dill <Russ.Dill@asu.edu>
++ * taken from pc_keyb.c
++ *
++ * This code grabs keypresses from the input layer and makes them
++ * available to the console.
++ *
++ * 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 <asm/uaccess.h>
++#include <asm/keyboard.h>
++
++/* Simple translation table for the SysRq keys */
++
++unsigned char input_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 */
++
++/*
++ * 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
++
++/*
++ * 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
++
++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, 0, 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, 0, 0, E0_PRSCR, /* 0x30-0x37 */
++ E0_RALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */
++ 0, 0, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */
++ E0_UP, E0_PGUP, 0, E0_LEFT, 0, E0_RIGHT, 0, E0_END, /* 0x48-0x4f */
++ E0_DOWN, E0_PGDN, 0, 0, 0, 0, 0, 0, /* 0x50-0x57 */
++ 0, 0, 0, E0_MSLW, 0, 0, 0, 0, /* 0x58-0x5f */
++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68-0x6f */
++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
++ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
++};
++
++int input_setkeycode(unsigned int scancode, unsigned int keycode)
++{
++ if (scancode > 255 || keycode > 127) return -EINVAL;
++ e0_keys[scancode - 128] = keycode;
++ return 0;
++}
++
++int input_getkeycode(unsigned int scancode)
++{
++ return scancode > 255 ? -EINVAL : e0_keys[scancode - 128];
++}
++
++#define KBD_REPORT_UNKN
++int input_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;
++ }
++ 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;
++
++ 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
++ *keycode = scancode;
++ return 1;
++}
++
++char input_unexpected_up(unsigned char keycode)
++{
++ return 0200;
++}
++
++/* Allow for loadable keyboard drivers */
++EXPORT_SYMBOL(input_setkeycode);
++EXPORT_SYMBOL(input_unexpected_up);
++EXPORT_SYMBOL(input_translate);
++EXPORT_SYMBOL(input_sysrq_xlate);
++EXPORT_SYMBOL(input_getkeycode);
++EXPORT_SYMBOL(k_setkeycode);
++EXPORT_SYMBOL(k_unexpected_up);
++EXPORT_SYMBOL(k_translate);
++EXPORT_SYMBOL(k_getkeycode);
++#ifdef CONFIG_MAGIC_SYSRQ
++EXPORT_SYMBOL(k_sysrq_key);
++EXPORT_SYMBOL(k_sysrq_xlate);
++#endif
+--- linux-2.4.21/drivers/char/keyboard.c~wedge
++++ linux-2.4.21/drivers/char/keyboard.c
+@@ -77,6 +77,7 @@
+ void (*kbd_ledfunc)(unsigned int led);
+ EXPORT_SYMBOL(handle_scancode);
+ EXPORT_SYMBOL(kbd_ledfunc);
++EXPORT_SYMBOL(key_maps);
+ EXPORT_SYMBOL(kbd_refresh_leds);
+
+ extern void ctrl_alt_del(void);
+--- linux-2.4.21/drivers/char/serial.c~ramses-serial
++++ linux-2.4.21/drivers/char/serial.c
+@@ -1,138 +1,8 @@
+-/*
+- * linux/drivers/char/serial.c
+- *
+- * Copyright (C) 1991, 1992 Linus Torvalds
+- * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
+- * 1998, 1999 Theodore Ts'o
+- *
+- * Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now
+- * much more extensible to support other serial cards based on the
+- * 16450/16550A UART's. Added support for the AST FourPort and the
+- * Accent Async board.
+- *
+- * set_serial_info fixed to set the flags, custom divisor, and uart
+- * type fields. Fix suggested by Michael K. Johnson 12/12/92.
+- *
+- * 11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis <ah@doc.ic.ac.uk>
+- *
+- * 03/96: Modularised by Angelo Haritsis <ah@doc.ic.ac.uk>
+- *
+- * rs_set_termios fixed to look also for changes of the input
+- * flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK.
+- * Bernd Anhäupl 05/17/96.
+- *
+- * 1/97: Extended dumb serial ports are a config option now.
+- * Saves 4k. Michael A. Griffith <grif@acm.org>
+- *
+- * 8/97: Fix bug in rs_set_termios with RTS
+- * Stanislav V. Voronyi <stas@uanet.kharkov.ua>
+- *
+- * 3/98: Change the IRQ detection, use of probe_irq_o*(),
+- * suppress TIOCSERGWILD and TIOCSERSWILD
+- * Etienne Lorrain <etienne.lorrain@ibm.net>
+- *
+- * 4/98: Added changes to support the ARM architecture proposed by
+- * Russell King
+- *
+- * 5/99: Updated to include support for the XR16C850 and ST16C654
+- * uarts. Stuart MacDonald <stuartm@connecttech.com>
+- *
+- * 8/99: Generalized PCI support added. Theodore Ts'o
+- *
+- * 3/00: Rid circular buffer of redundant xmit_cnt. Fix a
+- * few races on freeing buffers too.
+- * Alan Modra <alan@linuxcare.com>
+- *
+- * 5/00: Support for the RSA-DV II/S card added.
+- * Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
+- *
+- * 6/00: Remove old-style timer, use timer_list
+- * Andrew Morton <andrewm@uow.edu.au>
+- *
+- * 7/00: Support Timedia/Sunix/Exsys PCI cards
+- *
+- * 7/00: fix some returns on failure not using MOD_DEC_USE_COUNT.
+- * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+- *
+- * 10/00: add in optional software flow control for serial console.
+- * Kanoj Sarcar <kanoj@sgi.com> (Modified by Theodore Ts'o)
+- *
+- * 02/02: Fix for AMD Elan bug in transmit irq routine, by
+- * Christer Weinigel <wingel@hog.ctrl-c.liu.se>,
+- * Robert Schwebel <robert@schwebel.de>,
+- * Juergen Beisert <jbeisert@eurodsn.de>,
+- * Theodore Ts'o <tytso@mit.edu>
+- */
+-
+-static char *serial_version = "5.05c";
+-static char *serial_revdate = "2001-07-08";
+-
+-/*
+- * Serial driver configuration section. Here are the various options:
+- *
+- * CONFIG_HUB6
+- * Enables support for the venerable Bell Technologies
+- * HUB6 card.
+- *
+- * CONFIG_SERIAL_MANY_PORTS
+- * Enables support for ports beyond the standard, stupid
+- * COM 1/2/3/4.
+- *
+- * CONFIG_SERIAL_MULTIPORT
+- * Enables support for special multiport board support.
+- *
+- * CONFIG_SERIAL_SHARE_IRQ
+- * Enables support for multiple serial ports on one IRQ
+- *
+- * CONFIG_SERIAL_DETECT_IRQ
+- * Enable the autodetection of IRQ on standart ports
+- *
+- * SERIAL_PARANOIA_CHECK
+- * Check the magic number for the async_structure where
+- * ever possible.
+- *
+- * CONFIG_SERIAL_ACPI
+- * Enable support for serial console port and serial
+- * debug port as defined by the SPCR and DBGP tables in
+- * ACPI 2.0.
+- */
++#undef DEBUG
+
+ #include <linux/config.h>
+ #include <linux/version.h>
+
+-#undef SERIAL_PARANOIA_CHECK
+-#define CONFIG_SERIAL_NOPAUSE_IO
+-#define SERIAL_DO_RESTART
+-
+-#if 0
+-/* These defines are normally controlled by the autoconf.h */
+-#define CONFIG_SERIAL_MANY_PORTS
+-#define CONFIG_SERIAL_SHARE_IRQ
+-#define CONFIG_SERIAL_DETECT_IRQ
+-#define CONFIG_SERIAL_MULTIPORT
+-#define CONFIG_HUB6
+-#endif
+-
+-#ifdef CONFIG_PCI
+-#define ENABLE_SERIAL_PCI
+-#ifndef CONFIG_SERIAL_SHARE_IRQ
+-#define CONFIG_SERIAL_SHARE_IRQ
+-#endif
+-#ifndef CONFIG_SERIAL_MANY_PORTS
+-#define CONFIG_SERIAL_MANY_PORTS
+-#endif
+-#endif
+-
+-#ifdef CONFIG_SERIAL_ACPI
+-#define ENABLE_SERIAL_ACPI
+-#endif
+-
+-#if defined(CONFIG_ISAPNP)|| (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
+-#ifndef ENABLE_SERIAL_PNP
+-#define ENABLE_SERIAL_PNP
+-#endif
+-#endif
+-
+ #ifdef CONFIG_ARCH_PXA
+ #define pxa_port(x) ((x) == PORT_PXA)
+ #define pxa_buggy_port(x) ({ \
+@@ -149,39 +19,16 @@
+ #undef SERIAL_DEBUG_OPEN
+ #undef SERIAL_DEBUG_FLOW
+ #undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+-#undef SERIAL_DEBUG_PCI
+-#undef SERIAL_DEBUG_AUTOCONF
+
+ /* Sanity checks */
+
+-#ifdef CONFIG_SERIAL_MULTIPORT
+-#ifndef CONFIG_SERIAL_SHARE_IRQ
+-#define CONFIG_SERIAL_SHARE_IRQ
+-#endif
+-#endif
+-
+-#ifdef CONFIG_HUB6
+-#ifndef CONFIG_SERIAL_MANY_PORTS
+-#define CONFIG_SERIAL_MANY_PORTS
+-#endif
+-#ifndef CONFIG_SERIAL_SHARE_IRQ
+-#define CONFIG_SERIAL_SHARE_IRQ
+-#endif
+-#endif
+-
+ #ifdef MODULE
+ #undef CONFIG_SERIAL_CONSOLE
+ #endif
+
+-#define CONFIG_SERIAL_RSA
+-
+ #define RS_STROBE_TIME (10*HZ)
+ #define RS_ISR_PASS_LIMIT 256
+
+-#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
+-#define SERIAL_INLINE
+-#endif
+-
+ /*
+ * End of serial driver configuration section.
+ */
+@@ -213,53 +60,51 @@
+ #include <linux/ioport.h>
+ #include <linux/mm.h>
+ #include <linux/slab.h>
+-#if (LINUX_VERSION_CODE >= 131343)
+ #include <linux/init.h>
+-#endif
+-#if (LINUX_VERSION_CODE >= 131336)
+ #include <asm/uaccess.h>
+-#endif
+ #include <linux/delay.h>
+ #ifdef CONFIG_SERIAL_CONSOLE
+ #include <linux/console.h>
+ #endif
+-#ifdef ENABLE_SERIAL_PCI
+-#include <linux/pci.h>
+-#endif
+-#ifdef ENABLE_SERIAL_PNP
+-#include <linux/isapnp.h>
+-#endif
+ #ifdef CONFIG_MAGIC_SYSRQ
+ #include <linux/sysrq.h>
+ #endif
+
+-/*
+- * All of the compatibilty code so we can compile serial.c against
+- * older kernels is hidden in serial_compat.h
+- */
+-#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
+-#include "serial_compat.h"
+-#endif
+-
+ #include <asm/system.h>
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/bitops.h>
+
+-#if defined(CONFIG_MAC_SERIAL)
+-#define SERIAL_DEV_OFFSET ((_machine == _MACH_prep || _machine == _MACH_chrp) ? 0 : 2)
+-#else
+-#define SERIAL_DEV_OFFSET 0
+-#endif
++#define _INLINE_
+
+-#ifdef SERIAL_INLINE
+-#define _INLINE_ inline
++/*
++ * The TI16754 has 4 UARTS. They are selected with nCS3 and some
++ * address bits:
++ *
++ * 12 8 4
++ * nA8, nCS[3] for MN_UART_1, address mask 1110 1110 0000 0000 = 0xEE00
++ * nA9, nCS[3] for MN_UART_1, address mask 1110 1101 0000 0000 = 0xED00
++ * nA10, nCS[3] for MN_UART_1, address mask 1110 1011 0000 0000 = 0xEB00
++ * nA11, nCS[3] for MN_UART_1, address mask 1110 0111 0000 0000 = 0xE700
++ */
++#define RAMSES_UARTA_PHYS (PXA_CS3_PHYS+0xEE00)
++#define RAMSES_UARTB_PHYS (PXA_CS3_PHYS+0xED00)
++#define RAMSES_UARTC_PHYS (PXA_CS3_PHYS+0xEB00)
++#define RAMSES_UARTD_PHYS (PXA_CS3_PHYS+0xE700)
++static void *ramses_uarta; // address cookie for UART A
++static void *ramses_uartb; // address cookie for UART B
++static void *ramses_uartc; // address cookie for UART C/Scanner
++static void *ramses_uartd; // address cookie for UART D
++static int ramses_stay_on = 0;
++
++#ifdef DEBUG
++#define DPRINTK(fmt,args...) printk("//HS " fmt, ## args)
++static int show_io = 1;
+ #else
+-#define _INLINE_
++#define DPRINTK(fmt,args...)
++static int show_io = 0;
+ #endif
+
+-static char *serial_name = "Serial driver";
+-
+ static DECLARE_TASK_QUEUE(tq_serial);
+
+ static struct tty_driver serial_driver, callout_driver;
+@@ -282,9 +127,6 @@
+ */
+
+ static struct async_struct *IRQ_ports[NR_IRQS];
+-#ifdef CONFIG_SERIAL_MULTIPORT
+-static struct rs_multiport_struct rs_multiport[NR_IRQS];
+-#endif
+ static int IRQ_timeout[NR_IRQS];
+ #ifdef CONFIG_SERIAL_CONSOLE
+ static struct console sercons;
+@@ -294,8 +136,6 @@
+ static unsigned long break_pressed; /* break, really ... */
+ #endif
+
+-static unsigned detect_uart_irq (struct serial_state * state);
+-static void autoconfig(struct serial_state * state);
+ static void change_speed(struct async_struct *info, struct termios *old);
+ static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+
+@@ -325,46 +165,74 @@
+ { 0, 0}
+ };
+
+-#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
+-
+-#define PORT_RSA_MAX 4
+-static int probe_rsa[PORT_RSA_MAX];
+-static int force_rsa[PORT_RSA_MAX];
+-
+-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_RSA */
+-
+-struct serial_state rs_table[RS_TABLE_SIZE] = {
+- SERIAL_PORT_DFNS /* Defined in serial.h */
++static struct serial_state rs_table[] = {
++ {
++ type: PORT_PXA,
++ xmit_fifo_size: 32,
++ baud_base: 921600,
++ iomem_base: (void *)&FFUART,
++ iomem_reg_shift: 2,
++ io_type: SERIAL_IO_MEM32,
++ irq: IRQ_FFUART,
++ flags: ASYNC_SKIP_TEST,
++ }, {
++ type: PORT_PXA,
++ xmit_fifo_size: 32,
++ baud_base: 921600,
++ iomem_base: (void *)&BTUART,
++ iomem_reg_shift: 2,
++ io_type: SERIAL_IO_MEM32,
++ irq: IRQ_BTUART,
++ flags: ASYNC_SKIP_TEST,
++ }, {
++ type: PORT_PXA,
++ xmit_fifo_size: 32,
++ baud_base: 921600,
++ iomem_base: (void *)&STUART,
++ iomem_reg_shift: 2,
++ io_type: SERIAL_IO_MEM32,
++ irq: IRQ_STUART,
++ flags: ASYNC_SKIP_TEST,
++ }, {
++ type: PORT_16750,
++ xmit_fifo_size: 64,
++ baud_base: 115200*2,
++ iomem_base: (void *)0,
++ iomem_reg_shift: 2,
++ io_type: SERIAL_IO_MEM,
++ irq: IRQ_GPIO(7),
++ flags: ASYNC_SKIP_TEST,
++ }, {
++ type: PORT_16750,
++ xmit_fifo_size: 64,
++ baud_base: 115200*2,
++ iomem_base: (void *)0,
++ iomem_reg_shift: 2,
++ io_type: SERIAL_IO_MEM,
++ irq: IRQ_GPIO(24),
++ flags: ASYNC_SKIP_TEST,
++ }, {
++ type: PORT_16750,
++ xmit_fifo_size: 64,
++ baud_base: 115200*2,
++ iomem_base: (void *)0,
++ iomem_reg_shift: 2,
++ io_type: SERIAL_IO_MEM,
++ irq: IRQ_GPIO(25),
++ flags: ASYNC_SKIP_TEST,
++ }, {
++ type: PORT_16750,
++ xmit_fifo_size: 64,
++ baud_base: 115200*2,
++ iomem_base: (void *)0,
++ iomem_reg_shift: 2,
++ io_type: SERIAL_IO_MEM,
++ irq: IRQ_GPIO(26),
++ flags: ASYNC_SKIP_TEST,
++ }
+ };
+
+ #define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
+-int serial_nr_ports = NR_PORTS;
+-
+-#if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP))
+-#define NR_PCI_BOARDS 8
+-
+-static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
+-
+-#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
+-#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
+
+ #ifndef PREPARE_FUNC
+ #define PREPARE_FUNC(dev) (dev->prepare)
+@@ -403,39 +271,21 @@
+ #endif
+
+
+-static inline int serial_paranoia_check(struct async_struct *info,
+- kdev_t device, const char *routine)
+-{
+-#ifdef SERIAL_PARANOIA_CHECK
+- static const char *badmagic =
+- "Warning: bad magic number for serial struct (%s) in %s\n";
+- static const char *badinfo =
+- "Warning: null async_struct for (%s) in %s\n";
+-
+- if (!info) {
+- printk(badinfo, kdevname(device), routine);
+- return 1;
+- }
+- if (info->magic != SERIAL_MAGIC) {
+- printk(badmagic, kdevname(device), routine);
+- return 1;
+- }
+-#endif
+- return 0;
+-}
+-
+ static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
+ {
++ unsigned int value;
+ switch (info->io_type) {
+-#ifdef CONFIG_HUB6
+- case SERIAL_IO_HUB6:
+- outb(info->hub6 - 1 + offset, info->port);
+- return inb(info->port+1);
+-#endif
+ case SERIAL_IO_MEM:
+- return readb((unsigned long) info->iomem_base +
++ value = readb((unsigned long) info->iomem_base +
+ (offset<<info->iomem_reg_shift));
++ udelay(10);
++ if (show_io) printk("in %02x = %02x\n", offset, value);
++ return value;
+ case SERIAL_IO_MEM32:
++ value = readl((unsigned long) info->iomem_base +
++ (offset<<info->iomem_reg_shift));
++ if (show_io) printk("in %02x = %02x\n", offset, value);
++ return value;
+ return readl((unsigned long) info->iomem_base +
+ (offset<<info->iomem_reg_shift));
+ default:
+@@ -447,17 +297,14 @@
+ int value)
+ {
+ switch (info->io_type) {
+-#ifdef CONFIG_HUB6
+- case SERIAL_IO_HUB6:
+- outb(info->hub6 - 1 + offset, info->port);
+- outb(value, info->port+1);
+- break;
+-#endif
+ case SERIAL_IO_MEM:
++ if (show_io) printk("out %02x, %02x\n", offset, value);
+ writeb(value, (unsigned long) info->iomem_base +
+ (offset<<info->iomem_reg_shift));
++ udelay(10);
+ break;
+ case SERIAL_IO_MEM32:
++ if (show_io) printk("out %02x, %02x\n", offset, value);
+ writel(value, (unsigned long) info->iomem_base +
+ (offset<<info->iomem_reg_shift));
+ break;
+@@ -509,9 +356,6 @@
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+- if (serial_paranoia_check(info, tty->device, "rs_stop"))
+- return;
+-
+ save_flags(flags); cli();
+ if (info->IER & UART_IER_THRI) {
+ info->IER &= ~UART_IER_THRI;
+@@ -529,9 +373,6 @@
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+- if (serial_paranoia_check(info, tty->device, "rs_start"))
+- return;
+-
+ save_flags(flags); cli();
+ if (info->xmit.head != info->xmit.tail
+ && info->xmit.buf
+@@ -689,11 +530,7 @@
+ #endif
+ *status = serial_inp(info, UART_LSR);
+ } while ((*status & UART_LSR_DR) && (max_count-- > 0));
+-#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
+ tty_flip_buffer_push(tty);
+-#else
+- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+-#endif
+ }
+
+ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
+@@ -758,11 +595,6 @@
+ icount->dsr++;
+ if (status & UART_MSR_DDCD) {
+ icount->dcd++;
+-#ifdef CONFIG_HARD_PPS
+- if ((info->flags & ASYNC_HARDPPS_CD) &&
+- (status & UART_MSR_DCD))
+- hardpps();
+-#endif
+ }
+ if (status & UART_MSR_DCTS)
+ icount->cts++;
+@@ -810,120 +642,23 @@
+ }
+ }
+
+-#ifdef CONFIG_SERIAL_SHARE_IRQ
+-/*
+- * This is the serial driver's generic interrupt routine
+- */
+-static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+-{
+- int status, iir;
+- struct async_struct * info;
+- int pass_counter = 0;
+- struct async_struct *end_mark = 0;
+-#ifdef CONFIG_SERIAL_MULTIPORT
+- int first_multi = 0;
+- struct rs_multiport_struct *multi;
+-#endif
+-
+-#ifdef SERIAL_DEBUG_INTR
+- printk("rs_interrupt(%d)...", irq);
+-#endif
+-
+- info = IRQ_ports[irq];
+- if (!info)
+- return;
+-
+-#ifdef CONFIG_SERIAL_MULTIPORT
+- multi = &rs_multiport[irq];
+- if (multi->port_monitor)
+- first_multi = inb(multi->port_monitor);
+-#endif
+-
+- do {
+- if (!info->tty ||
+- ((iir=serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) {
+- if (!end_mark)
+- end_mark = info;
+- goto next;
+- }
+-#ifdef SERIAL_DEBUG_INTR
+- printk("IIR = %x...", serial_in(info, UART_IIR));
+-#endif
+- end_mark = 0;
+-
+- info->last_active = jiffies;
+-
+- status = serial_inp(info, UART_LSR);
+-#ifdef SERIAL_DEBUG_INTR
+- printk("status = %x...", status);
+-#endif
+- if (status & UART_LSR_DR)
+- receive_chars(info, &status, regs);
+- check_modem_status(info);
+-#ifdef CONFIG_MELAN
+- if ((status & UART_LSR_THRE) ||
+- /* for buggy ELAN processors */
+- ((iir & UART_IIR_ID) == UART_IIR_THRI))
+- transmit_chars(info, 0);
+-#else
+- if (status & UART_LSR_THRE)
+- transmit_chars(info, 0);
+-#endif
+-
+- next:
+- info = info->next_port;
+- if (!info) {
+- info = IRQ_ports[irq];
+- if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+-#if 0
+- printk("rs loop break\n");
+-#endif
+- break; /* Prevent infinite loops */
+- }
+- continue;
+- }
+- } while (end_mark != info);
+-#ifdef CONFIG_SERIAL_MULTIPORT
+- if (multi->port_monitor)
+- printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
+- info->state->irq, first_multi,
+- inb(multi->port_monitor));
+-#endif
+-#ifdef SERIAL_DEBUG_INTR
+- printk("end.\n");
+-#endif
+-}
+-#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */
+-
+
+ /*
+ * This is the serial driver's interrupt routine for a single port
+ */
+ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+ {
+- int status, iir;
++ int status;
+ int pass_counter = 0;
+ struct async_struct * info;
+-#ifdef CONFIG_SERIAL_MULTIPORT
+- int first_multi = 0;
+- struct rs_multiport_struct *multi;
+-#endif
+
+ #ifdef SERIAL_DEBUG_INTR
+ printk("rs_interrupt_single(%d)...", irq);
+ #endif
+-
+ info = IRQ_ports[irq];
+ if (!info || !info->tty)
+ return;
+
+-#ifdef CONFIG_SERIAL_MULTIPORT
+- multi = &rs_multiport[irq];
+- if (multi->port_monitor)
+- first_multi = inb(multi->port_monitor);
+-#endif
+-
+- iir = serial_in(info, UART_IIR);
+ do {
+ status = serial_inp(info, UART_LSR);
+ #ifdef SERIAL_DEBUG_INTR
+@@ -932,120 +667,23 @@
+ if (status & UART_LSR_DR)
+ receive_chars(info, &status, regs);
+ check_modem_status(info);
+- if ((status & UART_LSR_THRE) ||
+- /* For buggy ELAN processors */
+- ((iir & UART_IIR_ID) == UART_IIR_THRI))
++ if (status & UART_LSR_THRE)
+ transmit_chars(info, 0);
+ if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+-#if SERIAL_DEBUG_INTR
++#if 0
+ printk("rs_single loop break.\n");
+ #endif
+ break;
+ }
+- iir = serial_in(info, UART_IIR);
+-#ifdef SERIAL_DEBUG_INTR
+- printk("IIR = %x...", iir);
+-#endif
+- } while ((iir & UART_IIR_NO_INT) == 0);
+- info->last_active = jiffies;
+-#ifdef CONFIG_SERIAL_MULTIPORT
+- if (multi->port_monitor)
+- printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",
+- info->state->irq, first_multi,
+- inb(multi->port_monitor));
+-#endif
+-#ifdef SERIAL_DEBUG_INTR
+- printk("end.\n");
+-#endif
+-}
+-
+-#ifdef CONFIG_SERIAL_MULTIPORT
+-/*
+- * This is the serial driver's for multiport boards
+- */
+-static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
+-{
+- int status;
+- struct async_struct * info;
+- int pass_counter = 0;
+- int first_multi= 0;
+- struct rs_multiport_struct *multi;
+-
+ #ifdef SERIAL_DEBUG_INTR
+- printk("rs_interrupt_multi(%d)...", irq);
++ printk("IIR = %x...", serial_in(info, UART_IIR));
+ #endif
+-
+- info = IRQ_ports[irq];
+- if (!info)
+- return;
+- multi = &rs_multiport[irq];
+- if (!multi->port1) {
+- /* Should never happen */
+- printk("rs_interrupt_multi: NULL port1!\n");
+- return;
+- }
+- if (multi->port_monitor)
+- first_multi = inb(multi->port_monitor);
+-
+- while (1) {
+- if (!info->tty ||
+- (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
+- goto next;
+-
++ } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
+ info->last_active = jiffies;
+-
+- status = serial_inp(info, UART_LSR);
+-#ifdef SERIAL_DEBUG_INTR
+- printk("status = %x...", status);
+-#endif
+- if (status & UART_LSR_DR)
+- receive_chars(info, &status, regs);
+- check_modem_status(info);
+- if (status & UART_LSR_THRE)
+- transmit_chars(info, 0);
+-
+- next:
+- info = info->next_port;
+- if (info)
+- continue;
+-
+- info = IRQ_ports[irq];
+- /*
+- * The user was a bonehead, and misconfigured their
+- * multiport info. Rather than lock up the kernel
+- * in an infinite loop, if we loop too many times,
+- * print a message and break out of the loop.
+- */
+- if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+- printk("Misconfigured multiport serial info "
+- "for irq %d. Breaking out irq loop\n", irq);
+- break;
+- }
+- if (multi->port_monitor)
+- printk("rs port monitor irq %d: 0x%x, 0x%x\n",
+- info->state->irq, first_multi,
+- inb(multi->port_monitor));
+- if ((inb(multi->port1) & multi->mask1) != multi->match1)
+- continue;
+- if (!multi->port2)
+- break;
+- if ((inb(multi->port2) & multi->mask2) != multi->match2)
+- continue;
+- if (!multi->port3)
+- break;
+- if ((inb(multi->port3) & multi->mask3) != multi->match3)
+- continue;
+- if (!multi->port4)
+- break;
+- if ((inb(multi->port4) & multi->mask4) != multi->match4)
+- continue;
+- break;
+- }
+ #ifdef SERIAL_DEBUG_INTR
+ printk("end.\n");
+ #endif
+ }
+-#endif
+
+ /*
+ * -------------------------------------------------------------------
+@@ -1107,22 +745,6 @@
+ if (!info)
+ continue;
+ save_flags(flags); cli();
+-#ifdef CONFIG_SERIAL_SHARE_IRQ
+- if (info->next_port) {
+- do {
+- serial_out(info, UART_IER, 0);
+- info->IER |= UART_IER_THRI;
+- serial_out(info, UART_IER, info->IER);
+- info = info->next_port;
+- } while (info);
+-#ifdef CONFIG_SERIAL_MULTIPORT
+- if (rs_multiport[i].port1)
+- rs_interrupt_multi(i, NULL, NULL);
+- else
+-#endif
+- rs_interrupt(i, NULL, NULL);
+- } else
+-#endif /* CONFIG_SERIAL_SHARE_IRQ */
+ rs_interrupt_single(i, NULL, NULL);
+ restore_flags(flags);
+ }
+@@ -1132,11 +754,7 @@
+
+ if (IRQ_ports[0]) {
+ save_flags(flags); cli();
+-#ifdef CONFIG_SERIAL_SHARE_IRQ
+- rs_interrupt(0, NULL, NULL);
+-#else
+ rs_interrupt_single(0, NULL, NULL);
+-#endif
+ restore_flags(flags);
+
+ mod_timer(&serial_timer, jiffies + IRQ_timeout[0]);
+@@ -1177,50 +795,6 @@
+ IRQ_timeout[irq] = (timeout > 3) ? timeout-2 : 1;
+ }
+
+-#ifdef CONFIG_SERIAL_RSA
+-/* Attempts to turn on the RSA FIFO. Returns zero on failure */
+-static int enable_rsa(struct async_struct *info)
+-{
+- unsigned char mode;
+- int result;
+- unsigned long flags;
+-
+- save_flags(flags); cli();
+- mode = serial_inp(info, UART_RSA_MSR);
+- result = mode & UART_RSA_MSR_FIFO;
+-
+- if (!result) {
+- serial_outp(info, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+- mode = serial_inp(info, UART_RSA_MSR);
+- result = mode & UART_RSA_MSR_FIFO;
+- }
+-
+- restore_flags(flags);
+- return result;
+-}
+-
+-/* Attempts to turn off the RSA FIFO. Returns zero on failure */
+-static int disable_rsa(struct async_struct *info)
+-{
+- unsigned char mode;
+- int result;
+- unsigned long flags;
+-
+- save_flags(flags); cli();
+- mode = serial_inp(info, UART_RSA_MSR);
+- result = !(mode & UART_RSA_MSR_FIFO);
+-
+- if (!result) {
+- serial_outp(info, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+- mode = serial_inp(info, UART_RSA_MSR);
+- result = !(mode & UART_RSA_MSR_FIFO);
+- }
+-
+- restore_flags(flags);
+- return result;
+-}
+-#endif /* CONFIG_SERIAL_RSA */
+-
+ static int startup(struct async_struct * info)
+ {
+ unsigned long flags;
+@@ -1228,9 +802,6 @@
+ void (*handler)(int, void *, struct pt_regs *);
+ struct serial_state *state= info->state;
+ unsigned long page;
+-#ifdef CONFIG_SERIAL_MANY_PORTS
+- unsigned short ICP;
+-#endif
+
+ page = get_zeroed_page(GFP_KERNEL);
+ if (!page)
+@@ -1258,6 +829,22 @@
+ printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+ #endif
+
++ // Special handling to give power to devices
++ switch (info->line) {
++ case 3:
++ //printk("gsm on\n");
++ RAMSES_GSM_ON();
++ break;
++ case 4:
++ //printk("uart on\n");
++ RAMSES_UART_ON();
++ break;
++ case 5:
++ //printk("scanner on\n");
++ RAMSES_SCANNER_ON();
++ break;
++ }
++
+ if (uart_config[state->type].flags & UART_STARTECH) {
+ /* Wake up UART */
+ serial_outp(info, UART_LCR, 0xBF);
+@@ -1305,25 +892,12 @@
+ serial_outp(info, UART_LCR, 0);
+ }
+
+-#ifdef CONFIG_SERIAL_RSA
+- /*
+- * If this is an RSA port, see if we can kick it up to the
+- * higher speed clock.
+- */
+- if (state->type == PORT_RSA) {
+- if (state->baud_base != SERIAL_RSA_BAUD_BASE &&
+- enable_rsa(info))
+- state->baud_base = SERIAL_RSA_BAUD_BASE;
+- if (state->baud_base == SERIAL_RSA_BAUD_BASE)
+- serial_outp(info, UART_RSA_FRR, 0);
+- }
+-#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;
++ //HS TODO: cerf keeps the clock on
+ case (long)&STUART: CKEN |= CKEN5_STUART; break;
+ }
+ }
+@@ -1344,6 +918,7 @@
+ /*
+ * Clear the interrupt registers.
+ */
++ (void) serial_inp(info, UART_IIR);
+ (void) serial_inp(info, UART_LSR);
+ (void) serial_inp(info, UART_RX);
+ (void) serial_inp(info, UART_IIR);
+@@ -1371,18 +946,8 @@
+ if (state->irq && (!IRQ_ports[state->irq] ||
+ !IRQ_ports[state->irq]->next_port)) {
+ if (IRQ_ports[state->irq]) {
+-#ifdef CONFIG_SERIAL_SHARE_IRQ
+- free_irq(state->irq, &IRQ_ports[state->irq]);
+-#ifdef CONFIG_SERIAL_MULTIPORT
+- if (rs_multiport[state->irq].port1)
+- handler = rs_interrupt_multi;
+- else
+-#endif
+- handler = rs_interrupt;
+-#else
+ retval = -EBUSY;
+ goto errout;
+-#endif /* CONFIG_SERIAL_SHARE_IRQ */
+ } else
+ handler = rs_interrupt_single;
+
+@@ -1417,12 +982,6 @@
+ info->MCR = 0;
+ if (info->tty->termios->c_cflag & CBAUD)
+ info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+-#ifdef CONFIG_SERIAL_MANY_PORTS
+- if (info->flags & ASYNC_FOURPORT) {
+- if (state->irq == 0)
+- info->MCR |= UART_MCR_OUT1;
+- } else
+-#endif
+ {
+ if (state->irq != 0)
+ info->MCR |= UART_MCR_OUT2;
+@@ -1437,18 +996,9 @@
+ */
+ info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+ if (pxa_port(state->type))
+- info->IER |= UART_IER_UUE | UART_IER_RTOIE;
++ info->IER |= UART_IER_UUE | UART_IER_RTOIE; //HS TODO: UART_IER_THRI for PXA uarts?
+ serial_outp(info, UART_IER, info->IER); /* enable interrupts */
+
+-#ifdef CONFIG_SERIAL_MANY_PORTS
+- if (info->flags & ASYNC_FOURPORT) {
+- /* Enable interrupts on the AST Fourport board */
+- ICP = (info->port & 0xFE0) | 0x01F;
+- outb_p(0x80, ICP);
+- (void) inb_p(ICP);
+- }
+-#endif
+-
+ /*
+ * And clear the interrupt registers again for luck.
+ */
+@@ -1469,7 +1019,6 @@
+ /*
+ * Set up the tty->alt_speed kludge
+ */
+-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+ if (info->tty) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ info->tty->alt_speed = 57600;
+@@ -1480,7 +1029,6 @@
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ info->tty->alt_speed = 460800;
+ }
+-#endif
+
+ /*
+ * and set the speed of the serial port
+@@ -1516,6 +1064,30 @@
+ state->irq);
+ #endif
+
++ switch (info->line) {
++ case 3:
++ if (ramses_stay_on & RAMSES_CONTROL_GSM_PWR) {
++ //printk("gsm on\n");
++ RAMSES_GSM_OFF();
++ }
++ //else printk("gsm stays on\n");
++ break;
++ case 4:
++ if (ramses_stay_on & RAMSES_CONTROL_UART_PWR) {
++ //printk("uart off\n");
++ RAMSES_UART_OFF();
++ }
++ //else printk("uart stays on\n");
++ break;
++ case 5:
++ if (ramses_stay_on & RAMSES_CONTROL_SCANNER_PWR) {
++ //printk("scanner off\n");
++ RAMSES_SCANNER_OFF();
++ }
++ //else printk("scanner on\n");
++ break;
++ }
++
+ save_flags(flags); cli(); /* Disable interrupts */
+
+ /*
+@@ -1561,13 +1133,6 @@
+
+ info->IER = 0;
+ serial_outp(info, UART_IER, 0x00); /* disable all intrs */
+-#ifdef CONFIG_SERIAL_MANY_PORTS
+- if (info->flags & ASYNC_FOURPORT) {
+- /* reset interrupts on the AST Fourport board */
+- (void) inb((info->port & 0xFE0) | 0x01F);
+- info->MCR |= UART_MCR_OUT1;
+- } else
+-#endif
+ info->MCR &= ~UART_MCR_OUT2;
+ if (pxa_buggy_port(state->type))
+ info->MCR ^= UART_MCR_OUT2;
+@@ -1586,16 +1151,6 @@
+ UART_FCR_CLEAR_XMIT));
+ serial_outp(info, UART_FCR, 0);
+
+-#ifdef CONFIG_SERIAL_RSA
+- /*
+- * Reset the RSA board back to 115kbps compat mode.
+- */
+- if ((state->type == PORT_RSA) &&
+- (state->baud_base == SERIAL_RSA_BAUD_BASE &&
+- disable_rsa(info)))
+- state->baud_base = SERIAL_RSA_BAUD_BASE_LO;
+-#endif
+-
+ #ifdef CONFIG_ARCH_PXA
+ if (state->type == PORT_PXA
+ #ifdef CONFIG_SERIAL_CONSOLE
+@@ -1634,37 +1189,6 @@
+ restore_flags(flags);
+ }
+
+-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+-static int baud_table[] = {
+- 0, 50, 75, 110, 134, 150, 200, 300,
+- 600, 1200, 1800, 2400, 4800, 9600, 19200,
+- 38400, 57600, 115200, 230400, 460800, 0 };
+-
+-static int tty_get_baud_rate(struct tty_struct *tty)
+-{
+- struct async_struct * info = (struct async_struct *)tty->driver_data;
+- unsigned int cflag, i;
+-
+- cflag = tty->termios->c_cflag;
+-
+- i = cflag & CBAUD;
+- if (i & CBAUDEX) {
+- i &= ~CBAUDEX;
+- if (i < 1 || i > 2)
+- tty->termios->c_cflag &= ~CBAUDEX;
+- else
+- i += 15;
+- }
+- if (i == 15) {
+- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+- i += 1;
+- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+- i += 2;
+- }
+- return baud_table[i];
+-}
+-#endif
+-
+ /*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+@@ -1711,12 +1235,6 @@
+ baud = tty_get_baud_rate(info->tty);
+ if (!baud)
+ baud = 9600; /* B0 transition handled in rs_set_termios */
+-#ifdef CONFIG_SERIAL_RSA
+- if ((info->state->type == PORT_RSA) &&
+- (info->state->baud_base != SERIAL_RSA_BAUD_BASE) &&
+- enable_rsa(info))
+- info->state->baud_base = SERIAL_RSA_BAUD_BASE;
+-#endif
+ baud_base = info->state->baud_base;
+ if (info->state->type == PORT_16C950) {
+ if (baud <= baud_base)
+@@ -1778,10 +1296,6 @@
+ if (uart_config[info->state->type].flags & UART_USE_FIFO) {
+ if ((info->state->baud_base / quot) < 2400)
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+-#ifdef CONFIG_SERIAL_RSA
+- else if (info->state->type == PORT_RSA)
+- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
+-#endif
+ else
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+ }
+@@ -1864,9 +1378,6 @@
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+- if (serial_paranoia_check(info, tty->device, "rs_put_char"))
+- return;
+-
+ if (!tty || !info->xmit.buf)
+ return;
+
+@@ -1888,9 +1399,6 @@
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+- if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+- return;
+-
+ if (info->xmit.head == info->xmit.tail
+ || tty->stopped
+ || tty->hw_stopped
+@@ -1900,8 +1408,6 @@
+ 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);
+ }
+
+@@ -1912,9 +1418,6 @@
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+- if (serial_paranoia_check(info, tty->device, "rs_write"))
+- return 0;
+-
+ if (!tty || !info->xmit.buf || !tmp_buf)
+ return 0;
+
+@@ -1978,11 +1481,6 @@
+ && !(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;
+ }
+@@ -1991,8 +1489,6 @@
+ {
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+- if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+- return 0;
+ return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+ }
+
+@@ -2000,8 +1496,6 @@
+ {
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+- if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+- return 0;
+ return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+ }
+
+@@ -2010,8 +1504,6 @@
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+- if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+- return;
+ save_flags(flags); cli();
+ info->xmit.head = info->xmit.tail = 0;
+ restore_flags(flags);
+@@ -2032,16 +1524,11 @@
+ {
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+- if (serial_paranoia_check(info, tty->device, "rs_send_char"))
+- return;
+-
+ info->x_char = ch;
+ if (ch) {
+ /* 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);
+ }
+ }
+
+@@ -2064,9 +1551,6 @@
+ tty->ldisc.chars_in_buffer(tty));
+ #endif
+
+- if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+- return;
+-
+ if (I_IXOFF(tty))
+ rs_send_xchar(tty, STOP_CHAR(tty));
+
+@@ -2089,9 +1573,6 @@
+ tty->ldisc.chars_in_buffer(tty));
+ #endif
+
+- if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+- return;
+-
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+@@ -2134,7 +1615,6 @@
+ tmp.close_delay = state->close_delay;
+ tmp.closing_wait = state->closing_wait;
+ tmp.custom_divisor = state->custom_divisor;
+- tmp.hub6 = state->hub6;
+ tmp.io_type = state->io_type;
+ if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+ return -EFAULT;
+@@ -2160,8 +1640,7 @@
+ new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
+
+ change_irq = new_serial.irq != state->irq;
+- change_port = (new_port != ((int) state->port)) ||
+- (new_serial.hub6 != state->hub6);
++ change_port = (new_port != ((int) state->port));
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if (change_irq || change_port ||
+@@ -2198,7 +1677,6 @@
+ if (new_serial.type) {
+ for (i = 0 ; i < NR_PORTS; i++)
+ if ((state != &rs_table[i]) &&
+- (rs_table[i].io_type == SERIAL_IO_PORT) &&
+ (rs_table[i].port == new_port) &&
+ rs_table[i].type)
+ return -EADDRINUSE;
+@@ -2220,18 +1698,11 @@
+ 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;
+-#if (LINUX_VERSION_CODE > 0x20100)
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+-#endif
+ info->xmit_fifo_size = state->xmit_fifo_size =
+ new_serial.xmit_fifo_size;
+
+ if ((state->type != PORT_UNKNOWN) && state->port) {
+-#ifdef CONFIG_SERIAL_RSA
+- if (old_state.type == PORT_RSA)
+- release_region(state->port + UART_RSA_BASE, 16);
+- else
+-#endif
+ release_region(state->port,8);
+ }
+ state->type = new_serial.type;
+@@ -2243,31 +1714,19 @@
+ shutdown(info);
+ state->irq = new_serial.irq;
+ info->port = state->port = new_port;
+- info->hub6 = state->hub6 = new_serial.hub6;
+- if (info->hub6)
+- info->io_type = state->io_type = SERIAL_IO_HUB6;
+- else if (info->io_type == SERIAL_IO_HUB6)
+- info->io_type = state->io_type = SERIAL_IO_PORT;
+ }
+ if ((state->type != PORT_UNKNOWN) && state->port) {
+-#ifdef CONFIG_SERIAL_RSA
+- if (state->type == PORT_RSA)
+- request_region(state->port + UART_RSA_BASE,
+- 16, "serial_rsa(set)");
+- else
+-#endif
+ request_region(state->port,8,"serial(set)");
+ }
+
+
+ check_and_exit:
+- if ((!state->port && !state->iomem_base) || !state->type)
++ if (!state->port || !state->type)
+ 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 (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ info->tty->alt_speed = 57600;
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+@@ -2276,7 +1735,6 @@
+ info->tty->alt_speed = 230400;
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ info->tty->alt_speed = 460800;
+-#endif
+ change_speed(info, 0);
+ }
+ } else
+@@ -2414,60 +1872,14 @@
+ return 0;
+ }
+
+-static int do_autoconfig(struct async_struct * info)
+-{
+- int irq, retval;
+-
+- if (!capable(CAP_SYS_ADMIN))
+- return -EPERM;
+-
+- if (info->state->count > 1)
+- return -EBUSY;
+-
+- shutdown(info);
+-
+- autoconfig(info->state);
+- if ((info->state->flags & ASYNC_AUTO_IRQ) &&
+- (info->state->port != 0 || info->state->iomem_base != 0) &&
+- (info->state->type != PORT_UNKNOWN)) {
+- irq = detect_uart_irq(info->state);
+- if (irq > 0)
+- info->state->irq = irq;
+- }
+-
+- retval = startup(info);
+- if (retval)
+- return retval;
+- return 0;
+-}
+-
+ /*
+ * rs_break() --- routine which turns the break handling on or off
+ */
+-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+-static void send_break( struct async_struct * info, int duration)
+-{
+- if (!CONFIGURED_SERIAL_PORT(info))
+- return;
+- current->state = TASK_INTERRUPTIBLE;
+- current->timeout = jiffies + duration;
+- cli();
+- info->LCR |= UART_LCR_SBC;
+- serial_out(info, UART_LCR, info->LCR);
+- schedule();
+- info->LCR &= ~UART_LCR_SBC;
+- serial_out(info, UART_LCR, info->LCR);
+- sti();
+-}
+-#else
+ static void rs_break(struct tty_struct *tty, int break_state)
+ {
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+- if (serial_paranoia_check(info, tty->device, "rs_break"))
+- return;
+-
+ if (!CONFIGURED_SERIAL_PORT(info))
+ return;
+ save_flags(flags); cli();
+@@ -2478,121 +1890,6 @@
+ serial_out(info, UART_LCR, info->LCR);
+ restore_flags(flags);
+ }
+-#endif
+-
+-#ifdef CONFIG_SERIAL_MULTIPORT
+-static int get_multiport_struct(struct async_struct * info,
+- struct serial_multiport_struct *retinfo)
+-{
+- struct serial_multiport_struct ret;
+- struct rs_multiport_struct *multi;
+-
+- multi = &rs_multiport[info->state->irq];
+-
+- ret.port_monitor = multi->port_monitor;
+-
+- ret.port1 = multi->port1;
+- ret.mask1 = multi->mask1;
+- ret.match1 = multi->match1;
+-
+- ret.port2 = multi->port2;
+- ret.mask2 = multi->mask2;
+- ret.match2 = multi->match2;
+-
+- ret.port3 = multi->port3;
+- ret.mask3 = multi->mask3;
+- ret.match3 = multi->match3;
+-
+- ret.port4 = multi->port4;
+- ret.mask4 = multi->mask4;
+- ret.match4 = multi->match4;
+-
+- ret.irq = info->state->irq;
+-
+- if (copy_to_user(retinfo,&ret,sizeof(*retinfo)))
+- return -EFAULT;
+- return 0;
+-}
+-
+-static int set_multiport_struct(struct async_struct * info,
+- struct serial_multiport_struct *in_multi)
+-{
+- struct serial_multiport_struct new_multi;
+- struct rs_multiport_struct *multi;
+- struct serial_state *state;
+- int was_multi, now_multi;
+- int retval;
+- void (*handler)(int, void *, struct pt_regs *);
+-
+- if (!capable(CAP_SYS_ADMIN))
+- return -EPERM;
+- state = info->state;
+-
+- if (copy_from_user(&new_multi, in_multi,
+- sizeof(struct serial_multiport_struct)))
+- return -EFAULT;
+-
+- if (new_multi.irq != state->irq || state->irq == 0 ||
+- !IRQ_ports[state->irq])
+- return -EINVAL;
+-
+- multi = &rs_multiport[state->irq];
+- was_multi = (multi->port1 != 0);
+-
+- multi->port_monitor = new_multi.port_monitor;
+-
+- if (multi->port1)
+- release_region(multi->port1,1);
+- multi->port1 = new_multi.port1;
+- multi->mask1 = new_multi.mask1;
+- multi->match1 = new_multi.match1;
+- if (multi->port1)
+- request_region(multi->port1,1,"serial(multiport1)");
+-
+- if (multi->port2)
+- release_region(multi->port2,1);
+- multi->port2 = new_multi.port2;
+- multi->mask2 = new_multi.mask2;
+- multi->match2 = new_multi.match2;
+- if (multi->port2)
+- request_region(multi->port2,1,"serial(multiport2)");
+-
+- if (multi->port3)
+- release_region(multi->port3,1);
+- multi->port3 = new_multi.port3;
+- multi->mask3 = new_multi.mask3;
+- multi->match3 = new_multi.match3;
+- if (multi->port3)
+- request_region(multi->port3,1,"serial(multiport3)");
+-
+- if (multi->port4)
+- release_region(multi->port4,1);
+- multi->port4 = new_multi.port4;
+- multi->mask4 = new_multi.mask4;
+- multi->match4 = new_multi.match4;
+- if (multi->port4)
+- request_region(multi->port4,1,"serial(multiport4)");
+-
+- now_multi = (multi->port1 != 0);
+-
+- if (IRQ_ports[state->irq]->next_port &&
+- (was_multi != now_multi)) {
+- free_irq(state->irq, &IRQ_ports[state->irq]);
+- if (now_multi)
+- handler = rs_interrupt_multi;
+- else
+- handler = rs_interrupt;
+-
+- retval = request_irq(state->irq, handler, SA_SHIRQ,
+- "serial", &IRQ_ports[state->irq]);
+- if (retval) {
+- printk("Couldn't reallocate serial interrupt "
+- "driver!!\n");
+- }
+- }
+- return 0;
+-}
+-#endif
+
+ static int rs_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+@@ -2601,12 +1898,6 @@
+ struct async_icount cprev, cnow; /* kernel counter temps */
+ struct serial_icounter_struct icount;
+ unsigned long flags;
+-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+- int retval, tmp;
+-#endif
+-
+- if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+- return -ENODEV;
+
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+@@ -2616,45 +1907,6 @@
+ }
+
+ switch (cmd) {
+-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+- case TCSBRK: /* SVID version: non-zero arg --> no break */
+- retval = tty_check_change(tty);
+- if (retval)
+- return retval;
+- tty_wait_until_sent(tty, 0);
+- if (signal_pending(current))
+- return -EINTR;
+- if (!arg) {
+- send_break(info, HZ/4); /* 1/4 second */
+- if (signal_pending(current))
+- return -EINTR;
+- }
+- return 0;
+- case TCSBRKP: /* support for POSIX tcsendbreak() */
+- retval = tty_check_change(tty);
+- if (retval)
+- return retval;
+- tty_wait_until_sent(tty, 0);
+- if (signal_pending(current))
+- return -EINTR;
+- send_break(info, arg ? arg*(HZ/10) : HZ/4);
+- if (signal_pending(current))
+- return -EINTR;
+- return 0;
+- case TIOCGSOFTCAR:
+- tmp = C_CLOCAL(tty) ? 1 : 0;
+- if (copy_to_user((void *)arg, &tmp, sizeof(int)))
+- return -EFAULT;
+- return 0;
+- case TIOCSSOFTCAR:
+- if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
+- return -EFAULT;
+-
+- tty->termios->c_cflag =
+- ((tty->termios->c_cflag & ~CLOCAL) |
+- (tmp ? CLOCAL : 0));
+- return 0;
+-#endif
+ case TIOCMGET:
+ return get_modem_info(info, (unsigned int *) arg);
+ case TIOCMBIS:
+@@ -2667,9 +1919,6 @@
+ case TIOCSSERIAL:
+ return set_serial_info(info,
+ (struct serial_struct *) arg);
+- case TIOCSERCONFIG:
+- return do_autoconfig(info);
+-
+ case TIOCSERGETLSR: /* Get line status register */
+ return get_lsr_info(info, (unsigned int *) arg);
+
+@@ -2679,15 +1928,6 @@
+ return -EFAULT;
+ return 0;
+
+-#ifdef CONFIG_SERIAL_MULTIPORT
+- case TIOCSERGETMULTI:
+- return get_multiport_struct(info,
+- (struct serial_multiport_struct *) arg);
+- case TIOCSERSETMULTI:
+- return set_multiport_struct(info,
+- (struct serial_multiport_struct *) arg);
+-#endif
+-
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+@@ -2754,6 +1994,39 @@
+ printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
+ return 0;
+
++ case TIOCSERSETMULTI:
++ switch (arg) {
++
++ // switch devices on
++ case 2: RAMSES_LCD_BLIGHT_ON(); break;
++ case 3: RAMSES_GSM_ON(); break;
++ case 4: RAMSES_UART_ON(); break;
++ case 5: RAMSES_SCANNER_ON(); break;
++ case 7: RAMSES_SCANNER_WAKE_ON(); break;
++ case 8: RAMSES_SCANNER_TRIG_ON(); break;
++ case 9: RAMSES_GSM_RESET_ON(); break;
++
++ // switch devices off
++ case 12: RAMSES_LCD_BLIGHT_OFF(); break;
++ case 13: RAMSES_GSM_OFF(); break;
++ case 14: RAMSES_UART_OFF(); break;
++ case 15: RAMSES_SCANNER_OFF(); break;
++ case 17: RAMSES_SCANNER_WAKE_OFF(); break;
++ case 18: RAMSES_SCANNER_TRIG_OFF(); break;
++ case 19: RAMSES_GSM_RESET_OFF(); break;
++
++ // disable automatic poweroff on file-handle close
++ case 23: ramses_stay_on |= RAMSES_CONTROL_GSM_PWR; break;
++ case 24: ramses_stay_on |= RAMSES_CONTROL_UART_PWR; break;
++ case 25: ramses_stay_on |= RAMSES_CONTROL_SCANNER_PWR; break;
++
++ // enable automatic poweroff on file-handle close
++ case 33: ramses_stay_on &= ~RAMSES_CONTROL_GSM_PWR; break;
++ case 34: ramses_stay_on &= ~RAMSES_CONTROL_UART_PWR; break;
++ case 35: ramses_stay_on &= ~RAMSES_CONTROL_SCANNER_PWR; break;
++ }
++ return 0;
++
+ default:
+ return -ENOIOCTLCMD;
+ }
+@@ -2801,18 +2074,6 @@
+ tty->hw_stopped = 0;
+ rs_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
+ }
+
+ /*
+@@ -2831,9 +2092,6 @@
+ struct serial_state *state;
+ unsigned long flags;
+
+- if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+- return;
+-
+ state = info->state;
+
+ save_flags(flags); cli();
+@@ -2933,10 +2191,7 @@
+ {
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ unsigned long orig_jiffies, char_time;
+- int lsr;
+-
+- if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+- return;
++ int lsr, old_show_io;
+
+ if (info->state->type == PORT_UNKNOWN)
+ return;
+@@ -2974,9 +2229,11 @@
+ printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+ printk("jiff=%lu...", jiffies);
+ #endif
++ old_show_io = show_io;
++ show_io = 0;
+ while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) {
+ #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+- printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
++ printk("lsr = %02x (jiff=%lu)...", lsr, jiffies);
+ #endif
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(char_time);
+@@ -2986,8 +2243,9 @@
+ break;
+ }
+ #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+- printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
++ printk("lsr = %02x (jiff=%lu)...done\n", lsr, jiffies);
+ #endif
++ show_io = old_show_io;
+ }
+
+ /*
+@@ -2998,9 +2256,6 @@
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ struct serial_state *state = info->state;
+
+- if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+- return;
+-
+ state = info->state;
+
+ rs_flush_buffer(tty);
+@@ -3036,12 +2291,8 @@
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+-#ifdef SERIAL_DO_RESTART
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+-#else
+- return -EAGAIN;
+-#endif
+ }
+
+ /*
+@@ -3114,14 +2365,10 @@
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ASYNC_INITIALIZED)) {
+-#ifdef SERIAL_DO_RESTART
+ if (info->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+-#else
+- retval = -EAGAIN;
+-#endif
+ break;
+ }
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+@@ -3223,16 +2470,12 @@
+ }
+ tty->driver_data = info;
+ info->tty = tty;
+- if (serial_paranoia_check(info, tty->device, "rs_open"))
+- return -ENODEV;
+
+ #ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+ info->state->count);
+ #endif
+-#if (LINUX_VERSION_CODE > 0x20100)
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+-#endif
+
+ /*
+ * This relies on lock_kernel() stuff so wants tidying for 2.5
+@@ -3254,12 +2497,8 @@
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+-#ifdef SERIAL_DO_RESTART
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+-#else
+- return -EAGAIN;
+-#endif
+ }
+
+ /*
+@@ -3313,17 +2552,14 @@
+ int ret;
+ unsigned long flags;
+
+- /*
+- * Return zero characters for ports not claimed by driver.
+- */
+- if (state->type == PORT_UNKNOWN) {
+- return 0; /* ignore unused ports */
+- }
+-
+ ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
+ state->line, uart_config[state->type].name,
+- (state->port ? state->port : (long)state->iomem_base),
+- state->irq);
++ state->port, state->irq);
++
++ if (!state->port || (state->type == PORT_UNKNOWN)) {
++ ret += sprintf(buf+ret, "\n");
++ return ret;
++ }
+
+ /*
+ * Figure out the current RS-232 lines
+@@ -3334,7 +2570,6 @@
+ info->magic = SERIAL_MAGIC;
+ info->port = state->port;
+ info->flags = state->flags;
+- info->hub6 = state->hub6;
+ info->io_type = state->io_type;
+ info->iomem_base = state->iomem_base;
+ info->iomem_reg_shift = state->iomem_reg_shift;
+@@ -3389,13 +2624,13 @@
+ }
+
+ static int rs_read_proc(char *page, char **start, off_t off, int count,
+- int *eof, void *data)
++ int *eof, void *data)
+ {
+ int i, len = 0, l;
+ off_t begin = 0;
+
+- len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n",
+- serial_version, LOCAL_VERSTRING, serial_revdate);
++ len += sprintf(page, "serial: %s\n",
++ LOCAL_VERSTRING);
+ for (i = 0; i < NR_PORTS && len < 4000; i++) {
+ l = line_info(page + len, &rs_table[i]);
+ len += l;
+@@ -3423,2038 +2658,63 @@
+ */
+
+ /*
+- * This routine prints out the appropriate serial driver version
+- * number, and identifies which options were configured into this
+- * driver.
+- */
+-static char serial_options[] __initdata =
+-#ifdef CONFIG_HUB6
+- " HUB-6"
+-#define SERIAL_OPT
+-#endif
+-#ifdef CONFIG_SERIAL_MANY_PORTS
+- " MANY_PORTS"
+-#define SERIAL_OPT
+-#endif
+-#ifdef CONFIG_SERIAL_MULTIPORT
+- " MULTIPORT"
+-#define SERIAL_OPT
+-#endif
+-#ifdef CONFIG_SERIAL_SHARE_IRQ
+- " SHARE_IRQ"
+-#define SERIAL_OPT
+-#endif
+-#ifdef CONFIG_SERIAL_DETECT_IRQ
+- " DETECT_IRQ"
+-#define SERIAL_OPT
+-#endif
+-#ifdef ENABLE_SERIAL_PCI
+- " SERIAL_PCI"
+-#define SERIAL_OPT
+-#endif
+-#ifdef ENABLE_SERIAL_PNP
+- " ISAPNP"
+-#define SERIAL_OPT
+-#endif
+-#ifdef ENABLE_SERIAL_ACPI
+- " SERIAL_ACPI"
+-#define SERIAL_OPT
+-#endif
+-#ifdef SERIAL_OPT
+- " enabled\n";
+-#else
+- " no serial options enabled\n";
+-#endif
+-#undef SERIAL_OPT
+-
+-static _INLINE_ void show_serial_version(void)
+-{
+- printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name,
+- serial_version, LOCAL_VERSTRING, serial_revdate,
+- serial_options);
+-}
+-
+-/*
+- * This routine detect the IRQ of a serial port by clearing OUT2 when
+- * no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at
+- * each time, as long as no other device permanently request the IRQ.
+- * If no IRQ is detected, or multiple IRQ appear, this function returns 0.
+- * The variable "state" and the field "state->port" should not be null.
+- */
+-static unsigned detect_uart_irq (struct serial_state * state)
+-{
+- int irq;
+- unsigned long irqs;
+- unsigned char save_mcr, save_ier;
+- struct async_struct scr_info; /* serial_{in,out} because HUB6 */
+-
+-#ifdef CONFIG_SERIAL_MANY_PORTS
+- unsigned char save_ICP=0; /* no warning */
+- unsigned short ICP=0;
+-
+- if (state->flags & ASYNC_FOURPORT) {
+- ICP = (state->port & 0xFE0) | 0x01F;
+- save_ICP = inb_p(ICP);
+- outb_p(0x80, ICP);
+- (void) inb_p(ICP);
+- }
+-#endif
+- scr_info.magic = SERIAL_MAGIC;
+- scr_info.state = state;
+- scr_info.port = state->port;
+- scr_info.flags = state->flags;
+-#ifdef CONFIG_HUB6
+- scr_info.hub6 = state->hub6;
+-#endif
+- scr_info.io_type = state->io_type;
+- scr_info.iomem_base = state->iomem_base;
+- scr_info.iomem_reg_shift = state->iomem_reg_shift;
+-
+- /* forget possible initially masked and pending IRQ */
+- probe_irq_off(probe_irq_on());
+- save_mcr = serial_inp(&scr_info, UART_MCR);
+- save_ier = serial_inp(&scr_info, UART_IER);
+- serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+-
+- irqs = probe_irq_on();
+- serial_outp(&scr_info, UART_MCR, 0);
+- udelay (10);
+- if (state->flags & ASYNC_FOURPORT) {
+- serial_outp(&scr_info, UART_MCR,
+- UART_MCR_DTR | UART_MCR_RTS);
+- } else {
+- serial_outp(&scr_info, UART_MCR,
+- UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
+- }
+- serial_outp(&scr_info, UART_IER, 0x0f); /* enable all intrs */
+- (void)serial_inp(&scr_info, UART_LSR);
+- (void)serial_inp(&scr_info, UART_RX);
+- (void)serial_inp(&scr_info, UART_IIR);
+- (void)serial_inp(&scr_info, UART_MSR);
+- serial_outp(&scr_info, UART_TX, 0xFF);
+- udelay (20);
+- irq = probe_irq_off(irqs);
+-
+- serial_outp(&scr_info, UART_MCR, save_mcr);
+- serial_outp(&scr_info, UART_IER, save_ier);
+-#ifdef CONFIG_SERIAL_MANY_PORTS
+- if (state->flags & ASYNC_FOURPORT)
+- outb_p(save_ICP, ICP);
+-#endif
+- return (irq > 0)? irq : 0;
+-}
+-
+-/*
+- * 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 async_struct *info)
+-{
+- unsigned char old_fcr, old_mcr, old_dll, old_dlm;
+- int count;
+-
+- old_fcr = serial_inp(info, UART_FCR);
+- old_mcr = serial_inp(info, UART_MCR);
+- serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO |
+- UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+- serial_outp(info, UART_MCR, UART_MCR_LOOP);
+- serial_outp(info, UART_LCR, UART_LCR_DLAB);
+- old_dll = serial_inp(info, UART_DLL);
+- old_dlm = serial_inp(info, UART_DLM);
+- serial_outp(info, UART_DLL, 0x01);
+- serial_outp(info, UART_DLM, 0x00);
+- serial_outp(info, UART_LCR, 0x03);
+- for (count = 0; count < 256; count++)
+- serial_outp(info, UART_TX, count);
+- mdelay(20);
+- for (count = 0; (serial_inp(info, UART_LSR) & UART_LSR_DR) &&
+- (count < 256); count++)
+- serial_inp(info, UART_RX);
+- serial_outp(info, UART_FCR, old_fcr);
+- serial_outp(info, UART_MCR, old_mcr);
+- serial_outp(info, UART_LCR, UART_LCR_DLAB);
+- serial_outp(info, UART_DLL, old_dll);
+- serial_outp(info, 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_startech_uarts(struct async_struct *info,
+- struct serial_state *state,
+- unsigned long flags)
+-{
+- unsigned char scratch, scratch2, scratch3, scratch4;
+-
+- /*
+- * 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)
+- */
+- if (state->type == PORT_16550A) {
+- /*
+- * 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).
+- */
+- info->ACR = 0;
+- serial_out(info, UART_LCR, 0xBF);
+- serial_out(info, UART_EFR, 0x10);
+- serial_out(info, UART_LCR, 0x00);
+- /* Check for Oxford Semiconductor 16C950 */
+- scratch = serial_icr_read(info, UART_ID1);
+- scratch2 = serial_icr_read(info, UART_ID2);
+- scratch3 = serial_icr_read(info, UART_ID3);
+-
+- if (scratch == 0x16 && scratch2 == 0xC9 &&
+- (scratch3 == 0x50 || scratch3 == 0x52 ||
+- scratch3 == 0x54)) {
+- state->type = PORT_16C950;
+- state->revision = serial_icr_read(info, UART_REV) |
+- (scratch3 << 8);
+- return;
+- }
+- }
+-
+- /*
+- * We check for a XR16C850 by setting DLL and DLM to 0, and
+- * then reading back DLL and DLM. If DLM reads back 0x10,
+- * then the UART is a XR16C850 and the DLL contains the chip
+- * revision. If DLM reads back 0x14, then the UART is a
+- * XR16C854.
+- *
+- */
+-
+- /* Save the DLL and DLM */
+-
+- serial_outp(info, UART_LCR, UART_LCR_DLAB);
+- scratch3 = serial_inp(info, UART_DLL);
+- scratch4 = serial_inp(info, UART_DLM);
+-
+- serial_outp(info, UART_DLL, 0);
+- serial_outp(info, UART_DLM, 0);
+- scratch2 = serial_inp(info, UART_DLL);
+- scratch = serial_inp(info, UART_DLM);
+- serial_outp(info, UART_LCR, 0);
+-
+- if (scratch == 0x10 || scratch == 0x14) {
+- if (scratch == 0x10)
+- state->revision = scratch2;
+- state->type = PORT_16850;
+- return;
+- }
+-
+- /* Restore the DLL and DLM */
+-
+- serial_outp(info, UART_LCR, UART_LCR_DLAB);
+- serial_outp(info, UART_DLL, scratch3);
+- serial_outp(info, UART_DLM, scratch4);
+- serial_outp(info, UART_LCR, 0);
+- /*
+- * 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(info) == 64)
+- state->type = PORT_16654;
+- else
+- state->type = PORT_16650V2;
+-}
+-
+-/*
+- * 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 serial_state * state)
+-{
+- unsigned char status1, status2, scratch, scratch2, scratch3;
+- unsigned char save_lcr, save_mcr;
+- struct async_struct *info, scr_info;
+- unsigned long flags;
+-
+- state->type = PORT_UNKNOWN;
+-
+-#ifdef SERIAL_DEBUG_AUTOCONF
+- printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line,
+- state->port, (unsigned) state->iomem_base);
+-#endif
+-
+- if (!CONFIGURED_SERIAL_PORT(state))
+- return;
+-
+- info = &scr_info; /* This is just for serial_{in,out} */
+-
+- info->magic = SERIAL_MAGIC;
+- info->state = state;
+- info->port = state->port;
+- info->flags = state->flags;
+-#ifdef CONFIG_HUB6
+- info->hub6 = state->hub6;
+-#endif
+- info->io_type = state->io_type;
+- info->iomem_base = state->iomem_base;
+- info->iomem_reg_shift = state->iomem_reg_shift;
+-
+- save_flags(flags); cli();
+-
+- if (!(state->flags & ASYNC_BUGGY_UART) &&
+- !state->iomem_base) {
+- /*
+- * 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.
+- */
+- scratch = serial_inp(info, UART_IER);
+- serial_outp(info, UART_IER, 0);
+-#ifdef __i386__
+- outb(0xff, 0x080);
+-#endif
+- scratch2 = serial_inp(info, UART_IER);
+- serial_outp(info, UART_IER, 0x0F);
+-#ifdef __i386__
+- outb(0, 0x080);
+-#endif
+- scratch3 = serial_inp(info, UART_IER);
+- serial_outp(info, UART_IER, scratch);
+- if (scratch2 || scratch3 != 0x0F) {
+-#ifdef SERIAL_DEBUG_AUTOCONF
+- printk("serial: ttyS%d: simple autoconfig failed "
+- "(%02x, %02x)\n", state->line,
+- scratch2, scratch3);
+-#endif
+- restore_flags(flags);
+- return; /* We failed; there's nothing here */
+- }
+- }
+-
+- save_mcr = serial_in(info, UART_MCR);
+- save_lcr = serial_in(info, 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 (!(state->flags & ASYNC_SKIP_TEST)) {
+- serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
+- status1 = serial_inp(info, UART_MSR) & 0xF0;
+- serial_outp(info, UART_MCR, save_mcr);
+- if (status1 != 0x90) {
+-#ifdef SERIAL_DEBUG_AUTOCONF
+- printk("serial: ttyS%d: no UART loopback failed\n",
+- state->line);
+-#endif
+- restore_flags(flags);
+- return;
+- }
+- }
+- serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */
+- serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */
+- serial_outp(info, UART_LCR, 0);
+- serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+- scratch = serial_in(info, UART_IIR) >> 6;
+- switch (scratch) {
+- case 0:
+- state->type = PORT_16450;
+- break;
+- case 1:
+- state->type = PORT_UNKNOWN;
+- break;
+- case 2:
+- state->type = PORT_16550;
+- break;
+- case 3:
+- state->type = PORT_16550A;
+- break;
+- }
+- if (state->type == PORT_16550A) {
+- /* Check for Startech UART's */
+- serial_outp(info, UART_LCR, UART_LCR_DLAB);
+- if (serial_in(info, UART_EFR) == 0) {
+- state->type = PORT_16650;
+- } else {
+- serial_outp(info, UART_LCR, 0xBF);
+- if (serial_in(info, UART_EFR) == 0)
+- autoconfig_startech_uarts(info, state, flags);
+- }
+- }
+- if (state->type == PORT_16550A) {
+- /* Check for TI 16750 */
+- serial_outp(info, UART_LCR, save_lcr | UART_LCR_DLAB);
+- serial_outp(info, UART_FCR,
+- UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+- scratch = serial_in(info, UART_IIR) >> 5;
+- if (scratch == 7) {
+- /*
+- * If this is a 16750, and not a cheap UART
+- * clone, then it should only go into 64 byte
+- * mode if the UART_FCR7_64BYTE bit was set
+- * while UART_LCR_DLAB was latched.
+- */
+- serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+- serial_outp(info, UART_LCR, 0);
+- serial_outp(info, UART_FCR,
+- UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+- scratch = serial_in(info, UART_IIR) >> 5;
+- if (scratch == 6)
+- state->type = PORT_16750;
+- }
+- serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+- }
+-#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
+- if (state->type == PORT_16550A) {
+- int i;
+-
+- for (i = 0 ; i < PORT_RSA_MAX ; ++i) {
+- if (!probe_rsa[i] && !force_rsa[i])
+- break;
+- if (((probe_rsa[i] != state->port) ||
+- check_region(state->port + UART_RSA_BASE, 16)) &&
+- (force_rsa[i] != state->port))
+- continue;
+- if (!enable_rsa(info))
+- continue;
+- state->type = PORT_RSA;
+- state->baud_base = SERIAL_RSA_BAUD_BASE;
+- break;
+- }
+- }
+-#endif
+- serial_outp(info, UART_LCR, save_lcr);
+- if (state->type == PORT_16450) {
+- scratch = serial_in(info, UART_SCR);
+- serial_outp(info, UART_SCR, 0xa5);
+- status1 = serial_in(info, UART_SCR);
+- serial_outp(info, UART_SCR, 0x5a);
+- status2 = serial_in(info, UART_SCR);
+- serial_outp(info, UART_SCR, scratch);
+-
+- if ((status1 != 0xa5) || (status2 != 0x5a))
+- state->type = PORT_8250;
+- }
+- state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size;
+-
+- if (state->type == PORT_UNKNOWN) {
+- restore_flags(flags);
+- return;
+- }
+-
+- if (info->port) {
+-#ifdef CONFIG_SERIAL_RSA
+- if (state->type == PORT_RSA)
+- request_region(info->port + UART_RSA_BASE, 16,
+- "serial_rsa(auto)");
+- else
+-#endif
+- request_region(info->port,8,"serial(auto)");
+- }
+-
+- /*
+- * Reset the UART.
+- */
+-#ifdef CONFIG_SERIAL_RSA
+- if (state->type == PORT_RSA)
+- serial_outp(info, UART_RSA_FRR, 0);
+-#endif
+- serial_outp(info, UART_MCR, save_mcr);
+- serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+- UART_FCR_CLEAR_RCVR |
+- UART_FCR_CLEAR_XMIT));
+- serial_outp(info, UART_FCR, 0);
+- (void)serial_in(info, UART_RX);
+- serial_outp(info, UART_IER, 0);
+-
+- restore_flags(flags);
+-}
+-
+-int register_serial(struct serial_struct *req);
+-void unregister_serial(int line);
+-
+-#if (LINUX_VERSION_CODE > 0x20100)
+-EXPORT_SYMBOL(register_serial);
+-EXPORT_SYMBOL(unregister_serial);
+-#else
+-static struct symbol_table serial_syms = {
+-#include <linux/symtab_begin.h>
+- X(register_serial),
+- X(unregister_serial),
+-#include <linux/symtab_end.h>
+-};
+-#endif
+-
+-
+-#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
+-
+-static void __devinit printk_pnp_dev_id(unsigned short vendor,
+- unsigned short device)
+-{
+- printk("%c%c%c%x%x%x%x",
+- 'A' + ((vendor >> 2) & 0x3f) - 1,
+- 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
+- 'A' + ((vendor >> 8) & 0x1f) - 1,
+- (device >> 4) & 0x0f,
+- device & 0x0f,
+- (device >> 12) & 0x0f,
+- (device >> 8) & 0x0f);
+-}
+-
+-static _INLINE_ 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);
+- }
+-
+- }
+-
+- /* HP's Diva chip puts the 4th/5th serial port further out, and
+- * some serial ports are supposed to be hidden on certain models.
+- */
+- if (dev->vendor == PCI_VENDOR_ID_HP &&
+- dev->device == PCI_DEVICE_ID_HP_SAS) {
+- switch (dev->subsystem_device) {
+- case 0x104B: /* Maestro */
+- if (idx == 3) idx++;
+- break;
+- case 0x1282: /* Everest / Longs Peak */
+- if (idx > 0) idx++;
+- if (idx > 2) idx++;
+- break;
+- }
+- if (idx > 2) {
+- offset = 0x18;
+- }
+- }
+-
+- 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);
+-}
+-
+-/*
+- * Common enabler code shared by both PCI and ISAPNP probes
+- */
+-static void __devinit start_pci_pnp_board(struct pci_dev *dev,
+- struct pci_board *board)
+-{
+- int k, line;
+- struct serial_struct serial_req;
+- int base_baud;
+-
+- if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
+- printk("serial: PNP device '");
+- printk_pnp_dev_id(dev->vendor, dev->device);
+- printk("' prepare failed\n");
+- return;
+- }
+-
+- if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
+- printk("serial: PNP device '");
+- printk_pnp_dev_id(dev->vendor, dev->device);
+- printk("' activate failed\n");
+- return;
+- }
+-
+- /*
+- * Run the initialization function, if any
+- */
+- if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0))
+- return;
+-
+- /*
+- * Register the serial board in the array if we need to
+- * shutdown the board on a module unload or card removal
+- */
+- if (DEACTIVATE_FUNC(dev) || board->init_fn) {
+- for (k=0; k < NR_PCI_BOARDS; k++)
+- if (serial_pci_board[k].dev == 0)
+- break;
+- if (k >= NR_PCI_BOARDS)
+- return;
+- serial_pci_board[k].board = *board;
+- serial_pci_board[k].dev = dev;
+- }
+-
+- 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;
+- serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
+-#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
+- line = register_serial(&serial_req);
+- if (line < 0)
+- break;
+- rs_table[line].baud_base = base_baud;
+- rs_table[line].dev = dev;
+- }
+-}
+-#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
+-
+-#ifdef ENABLE_SERIAL_PCI
+-/*
+- * 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.
+- *
+- * SIIG initialization functions exported for use by parport_serial.c module.
+- */
+-
+-#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)
+-
+-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;
+-}
+-EXPORT_SYMBOL(pci_siig10x_fn);
+-
+-#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)
+-
+-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;
+-}
+-EXPORT_SYMBOL(pci_siig20x_fn);
+-
+-/* 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);
+-
+-#ifdef SERIAL_DEBUG_PCI
+- printk(KERN_DEBUG " Subsystem ID %lx (intel 960)\n",
+- (unsigned long) board->subdevice);
+-#endif
+- /* 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;
+-}
+-
+-/*
+- * HP's Remote Management Console. The Diva chip came in several
+- * different versions. N-class, L2000 and A500 have two Diva chips, each
+- * with 3 UARTs (the third UART on the second chip is unused). Superdome
+- * and Keystone have one Diva chip with 3 UARTs. Some later machines have
+- * one Diva chip, but it has been expanded to 5 UARTs.
+- */
+-static int __devinit
+-pci_hp_diva(struct pci_dev *dev, struct pci_board *board, int enable)
+-{
+- if (!enable)
+- return 0;
+-
+- switch (dev->subsystem_device) {
+- case 0x1049: /* Prelude Diva 1 */
+- case 0x1223: /* Superdome */
+- case 0x1226: /* Keystone */
+- case 0x1282: /* Everest / Longs Peak */
+- board->num_ports = 3;
+- break;
+- case 0x104A: /* Prelude Diva 2 */
+- board->num_ports = 2;
+- break;
+- case 0x104B: /* Maestro */
+- board->num_ports = 4;
+- break;
+- case 0x1227: /* Powerbar */
+- board->num_ports = 1;
+- break;
+- }
+-
+- 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_b0_bt_2_921600,
+-
+- 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_1_115200,
+- 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,
+- pbn_hp_diva,
+-#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_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b0_bt_2_921600 */
+-
+- { 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, 1, 115200 }, /* pbn_b2_1_115200 */
+- { 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 },
+- { SPCI_FL_BASE0, 5, 115200, 8, 0, pci_hp_diva, 0}, /* pbn_hp_diva */
+-#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.
++ * The serial driver boot-time initialization code!
+ */
+-static int __devinit serial_pci_guess_board(struct pci_dev *dev,
+- struct pci_board *board)
++static int __init rs_init(void)
+ {
+- int num_iomem = 0, num_port = 0, first_port = -1;
+ int i;
++ struct serial_state * state;
+
+- /*
+- * 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++;
+- }
++ printk("pxa & ti16c754b serial driver\n");
++ set_GPIO_IRQ_edge(7, GPIO_RISING_EDGE);
++ set_GPIO_IRQ_edge(24, GPIO_RISING_EDGE);
++ set_GPIO_IRQ_edge(25, GPIO_RISING_EDGE);
++ set_GPIO_IRQ_edge(26, GPIO_RISING_EDGE);
+
+- /*
+- * 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 (!request_mem_region(RAMSES_UARTA_PHYS, 16*4, "Ramses UART A"))
++ printk(KERN_ERR "unable to reserve region\n");
++ else {
++ ramses_uarta = ioremap_nocache(RAMSES_UARTA_PHYS, 16*4);
++ if (!ramses_uarta)
++ printk(KERN_ERR "unable to map region\n");
++ else {
++ //printk("ramses_uarta cookie is: %08x\n", (unsigned int) ramses_uarta);
++ rs_table[3].iomem_base = ramses_uarta;
+ }
+-
+- /*
+- * 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;
+-}
+-
+-static int __devinit serial_init_one(struct pci_dev *dev,
+- const struct pci_device_id *ent)
+-{
+- struct pci_board *board, tmp;
+- int rc;
+-
+- 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 (%04x,%04x,%04x,%04x)\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));
+- }
+-
+- start_pci_pnp_board(dev, board);
+-
+- return 0;
+-}
+-
+-static void __devexit serial_remove_one(struct pci_dev *dev)
+-{
+- int i;
+-
+- /*
+- * Iterate through all of the ports finding those that belong
+- * to this PCI device.
+- */
+- for(i = 0; i < NR_PORTS; i++) {
+- if (rs_table[i].dev != dev)
+- continue;
+- unregister_serial(i);
+- rs_table[i].dev = 0;
++ if (!request_mem_region(RAMSES_UARTB_PHYS, 16*4, "Ramses UART B"))
++ printk(KERN_ERR "unable to reserve region\n");
++ else {
++ ramses_uartb = ioremap_nocache(RAMSES_UARTB_PHYS, 16*4);
++ if (!ramses_uartb)
++ printk(KERN_ERR "unable to map region\n");
++ else {
++ //printk("ramses_uartb cookie is: %08x\n", (unsigned int) ramses_uartb);
++ rs_table[4].iomem_base = ramses_uartb;
+ }
+- /*
+- * Now execute any board-specific shutdown procedure
+- */
+- for (i=0; i < NR_PCI_BOARDS; i++) {
+- struct pci_board_inst *brd = &serial_pci_board[i];
+-
+- if (serial_pci_board[i].dev != dev)
+- continue;
+- if (brd->board.init_fn)
+- (brd->board.init_fn)(brd->dev, &brd->board, 0);
+- if (DEACTIVATE_FUNC(brd->dev))
+- (DEACTIVATE_FUNC(brd->dev))(brd->dev);
+- serial_pci_board[i].dev = 0;
+ }
+-}
+-
+-
+-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_bt_2_921600 },
+-
+- /* 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_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_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_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_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 },
+-
+- /* HP Diva card */
+- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_SAS,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- pbn_hp_diva },
+- { PCI_VENDOR_ID_HP, 0x1290,
+- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+- pbn_b2_1_115200 },
+-
+-#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, },
+- { 0, }
+-};
+-
+-MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
+-
+-static struct pci_driver serial_pci_driver = {
+- name: "serial",
+- probe: serial_init_one,
+- remove: __devexit_p(serial_remove_one),
+- id_table: serial_pci_tbl,
+-};
+-
+-
+-/*
+- * Query PCI space for known serial boards
+- * If found, add them to the PCI device space in rs_table[]
+- *
+- * Accept a maximum of eight boards
+- *
+- */
+-static void __devinit probe_serial_pci(void)
+-{
+-#ifdef SERIAL_DEBUG_PCI
+- printk(KERN_DEBUG "Entered probe_serial_pci()\n");
+-#endif
+-
+- /* Register call PCI serial devices. Null out
+- * the driver name upon failure, as a signal
+- * not to attempt to unregister the driver later
+- */
+- if (pci_module_init (&serial_pci_driver) != 0)
+- serial_pci_driver.name = "";
+-
+-#ifdef SERIAL_DEBUG_PCI
+- printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
+-#endif
+- return;
+-}
+-
+-#endif /* ENABLE_SERIAL_PCI */
+-
+-#ifdef ENABLE_SERIAL_PNP
+-
+-struct pnp_board {
+- unsigned short vendor;
+- unsigned short device;
+-};
+-
+-static struct pnp_board pnp_devices[] __devinitdata = {
+- /* Archtek America Corp. */
+- /* Archtek SmartLink Modem 3334BT Plug & Play */
+- { ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
+- /* Anchor Datacomm BV */
+- /* SXPro 144 External Data Fax Modem Plug & Play */
+- { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0001) },
+- /* SXPro 288 External Data Fax Modem Plug & Play */
+- { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0002) },
+- /* Rockwell 56K ACF II Fax+Data+Voice Modem */
+- { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021) },
+- /* AZT3005 PnP SOUND DEVICE */
+- { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001) },
+- /* Best Data Products Inc. Smart One 336F PnP Modem */
+- { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
+- /* Boca Research */
+- /* Boca Complete Ofc Communicator 14.4 Data-FAX */
+- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
+- /* Boca Research 33,600 ACF Modem */
+- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400) },
+- /* Boca 33.6 Kbps Internal FD34FSVD */
+- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x3400) },
+- /* Boca 33.6 Kbps Internal FD34FSVD */
+- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
+- /* Best Data Products Inc. Smart One 336F PnP Modem */
+- { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
+- /* Computer Peripherals Inc */
+- /* EuroViVa CommCenter-33.6 SP PnP */
+- { ISAPNP_VENDOR('C', 'P', 'I'), ISAPNP_DEVICE(0x4050) },
+- /* Creative Labs */
+- /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
+- { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3001) },
+- /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
+- { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3011) },
+- /* Creative */
+- /* Creative Modem Blaster Flash56 DI5601-1 */
+- { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032) },
+- /* Creative Modem Blaster V.90 DI5660 */
+- { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001) },
+- /* FUJITSU */
+- /* Fujitsu 33600 PnP-I2 R Plug & Play */
+- { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0202) },
+- /* Fujitsu FMV-FX431 Plug & Play */
+- { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0205) },
+- /* Fujitsu 33600 PnP-I4 R Plug & Play */
+- { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0206) },
+- /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
+- { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0209) },
+- /* Archtek America Corp. */
+- /* Archtek SmartLink Modem 3334BT Plug & Play */
+- { ISAPNP_VENDOR('G', 'V', 'C'), ISAPNP_DEVICE(0x000F) },
+- /* Hayes */
+- /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
+- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x0001) },
+- /* Hayes Optima 336 V.34 + FAX + Voice PnP */
+- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000C) },
+- /* Hayes Optima 336B V.34 + FAX + Voice PnP */
+- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000D) },
+- /* Hayes Accura 56K Ext Fax Modem PnP */
+- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5670) },
+- /* Hayes Accura 56K Ext Fax Modem PnP */
+- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5674) },
+- /* Hayes Accura 56K Fax Modem PnP */
+- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5675) },
+- /* Hayes 288, V.34 + FAX */
+- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF000) },
+- /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
+- { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF001) },
+- /* IBM */
+- /* IBM Thinkpad 701 Internal Modem Voice */
+- { ISAPNP_VENDOR('I', 'B', 'M'), ISAPNP_DEVICE(0x0033) },
+- /* Intertex */
+- /* Intertex 28k8 33k6 Voice EXT PnP */
+- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC801) },
+- /* Intertex 33k6 56k Voice EXT PnP */
+- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC901) },
+- /* Intertex 28k8 33k6 Voice SP EXT PnP */
+- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD801) },
+- /* Intertex 33k6 56k Voice SP EXT PnP */
+- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD901) },
+- /* Intertex 28k8 33k6 Voice SP INT PnP */
+- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF401) },
+- /* Intertex 28k8 33k6 Voice SP EXT PnP */
+- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF801) },
+- /* Intertex 33k6 56k Voice SP EXT PnP */
+- { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF901) },
+- /* Kortex International */
+- /* KORTEX 28800 Externe PnP */
+- { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0x4522) },
+- /* KXPro 33.6 Vocal ASVD PnP */
+- { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0xF661) },
+- /* Lasat */
+- /* LASAT Internet 33600 PnP */
+- { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4040) },
+- /* Lasat Safire 560 PnP */
+- { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4540) },
+- /* Lasat Safire 336 PnP */
+- { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x5440) },
+- /* Microcom, Inc. */
+- /* Microcom TravelPorte FAST V.34 Plug & Play */
+- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x281) },
+- /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
+- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0336) },
+- /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
+- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0339) },
+- /* Microcom DeskPorte 28.8P Plug & Play */
+- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0342) },
+- /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
+- /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
+- /* Microcom DeskPorte 28.8S Internal Plug & Play */
+- { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0502) },
+- /* Motorola */
+- /* Motorola BitSURFR Plug & Play */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1105) },
+- /* Motorola TA210 Plug & Play */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1111) },
+- /* Motorola HMTA 200 (ISDN) Plug & Play */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1114) },
+- /* Motorola BitSURFR Plug & Play */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1115) },
+- /* Motorola Lifestyle 28.8 Internal */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1190) },
+- /* Motorola V.3400 Plug & Play */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1501) },
+- /* Motorola Lifestyle 28.8 V.34 Plug & Play */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1502) },
+- /* Motorola Power 28.8 V.34 Plug & Play */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1505) },
+- /* Motorola ModemSURFR External 28.8 Plug & Play */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1509) },
+- /* Motorola Premier 33.6 Desktop Plug & Play */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150A) },
+- /* Motorola VoiceSURFR 56K External PnP */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150F) },
+- /* Motorola ModemSURFR 56K External PnP */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1510) },
+- /* Motorola ModemSURFR 56K Internal PnP */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1550) },
+- /* Motorola ModemSURFR Internal 28.8 Plug & Play */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1560) },
+- /* Motorola Premier 33.6 Internal Plug & Play */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1580) },
+- /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15B0) },
+- /* Motorola VoiceSURFR 56K Internal PnP */
+- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0) },
+- /* Com 1 */
+- /* Deskline K56 Phone System PnP */
+- { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00A1) },
+- /* PC Rider K56 Phone System PnP */
+- { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00F2) },
+- /* Pace 56 Voice Internal Plug & Play Modem */
+- { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430) },
+- /* Generic */
+- /* Generic standard PC COM port */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
+- /* Generic 16550A-compatible COM port */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
+- /* Compaq 14400 Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000) },
+- /* Compaq 2400/9600 Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001) },
+- /* Dial-Up Networking Serial Cable between 2 PCs */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC031) },
+- /* Dial-Up Networking Parallel Cable between 2 PCs */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC032) },
+- /* Standard 9600 bps Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC100) },
+- /* Standard 14400 bps Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC101) },
+- /* Standard 28800 bps Modem*/
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC102) },
+- /* Standard Modem*/
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC103) },
+- /* Standard 9600 bps Modem*/
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC104) },
+- /* Standard 14400 bps Modem*/
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC105) },
+- /* Standard 28800 bps Modem*/
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC106) },
+- /* Standard Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC107) },
+- /* Standard 9600 bps Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC108) },
+- /* Standard 14400 bps Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC109) },
+- /* Standard 28800 bps Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10A) },
+- /* Standard Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10B) },
+- /* Standard 9600 bps Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10C) },
+- /* Standard 14400 bps Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10D) },
+- /* Standard 28800 bps Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10E) },
+- /* Standard Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10F) },
+- /* Standard PCMCIA Card Modem */
+- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x2000) },
+- /* Rockwell */
+- /* Modular Technology */
+- /* Rockwell 33.6 DPF Internal PnP */
+- /* Modular Technology 33.6 Internal PnP */
+- { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0030) },
+- /* Kortex International */
+- /* KORTEX 14400 Externe PnP */
+- { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0100) },
+- /* Viking Components, Inc */
+- /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
+- { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x4920) },
+- /* Rockwell */
+- /* British Telecom */
+- /* Modular Technology */
+- /* Rockwell 33.6 DPF External PnP */
+- /* BT Prologue 33.6 External PnP */
+- /* Modular Technology 33.6 External PnP */
+- { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x00A0) },
+- /* Viking 56K FAX INT */
+- { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262) },
+- /* SupraExpress 28.8 Data/Fax PnP modem */
+- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310) },
+- /* SupraExpress 33.6 Data/Fax PnP modem */
+- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1421) },
+- /* SupraExpress 33.6 Data/Fax PnP modem */
+- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1590) },
+- /* SupraExpress 33.6 Data/Fax PnP modem */
+- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1760) },
+- /* Phoebe Micro */
+- /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
+- { ISAPNP_VENDOR('T', 'E', 'X'), ISAPNP_DEVICE(0x0011) },
+- /* Archtek America Corp. */
+- /* Archtek SmartLink Modem 3334BT Plug & Play */
+- { ISAPNP_VENDOR('U', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
+- /* 3Com Corp. */
+- /* Gateway Telepath IIvi 33.6 */
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0000) },
+- /* Sportster Vi 14.4 PnP FAX Voicemail */
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0004) },
+- /* U.S. Robotics 33.6K Voice INT PnP */
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006) },
+- /* U.S. Robotics 33.6K Voice EXT PnP */
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0007) },
+- /* U.S. Robotics 33.6K Voice INT PnP */
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2002) },
+- /* U.S. Robotics 56K Voice INT PnP */
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2070) },
+- /* U.S. Robotics 56K Voice EXT PnP */
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2080) },
+- /* U.S. Robotics 56K FAX INT */
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031) },
+- /* U.S. Robotics 56K Voice INT PnP */
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3070) },
+- /* U.S. Robotics 56K Voice EXT PnP */
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3080) },
+- /* U.S. Robotics 56K Voice INT PnP */
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3090) },
+- /* U.S. Robotics 56K Message */
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9100) },
+- /* U.S. Robotics 56K FAX EXT PnP*/
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9160) },
+- /* U.S. Robotics 56K FAX INT PnP*/
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9170) },
+- /* U.S. Robotics 56K Voice EXT PnP*/
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9180) },
+- /* U.S. Robotics 56K Voice INT PnP*/
+- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9190) },
+- { 0, }
+-};
+-
+-static inline void 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 = modem_names;
+-
+- while (*tmp) {
+- if (strstr(name, *tmp))
+- return 1;
+- tmp++;
++ if (!request_mem_region(RAMSES_UARTC_PHYS, 16*4, "Ramses UART C"))
++ printk(KERN_ERR "unable to reserve region\n");
++ else {
++ ramses_uartc = ioremap_nocache(RAMSES_UARTC_PHYS, 16*4);
++ if (!ramses_uartc)
++ printk(KERN_ERR "unable to map region\n");
++ else {
++ //printk("ramses_uartc cookie is: %08x\n", (unsigned int) ramses_uartc);
++ rs_table[5].iomem_base = ramses_uartc;
+ }
+- return 0;
+-}
+-
+-static inline int 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 _INLINE_ serial_pnp_guess_board(struct pci_dev *dev,
+- struct pci_board *board)
+-{
+- 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 1;
+-
+- if (!res || res->next)
+- return 1;
+-
+- 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 1;
+-}
+-
+-static void __devinit probe_serial_pnp(void)
+-{
+- struct pci_dev *dev = NULL;
+- struct pnp_board *pnp_board;
+- struct pci_board board;
+-
+-#ifdef SERIAL_DEBUG_PNP
+- printk("Entered probe_serial_pnp()\n");
+-#endif
+- if (!isapnp_present()) {
+-#ifdef SERIAL_DEBUG_PNP
+- printk("Leaving probe_serial_pnp() (no isapnp)\n");
+-#endif
+- return;
++ if (!request_mem_region(RAMSES_UARTD_PHYS, 16*4, "Ramses UART D"))
++ printk(KERN_ERR "unable to reserve region\n");
++ else {
++ ramses_uartd = ioremap_nocache(RAMSES_UARTD_PHYS, 16*4);
++ if (!ramses_uartd)
++ printk(KERN_ERR "unable to map region\n");
++ else {
++ //printk("ramses_uartd cookie is: %08x\n", (unsigned int) ramses_uartd);
++ rs_table[6].iomem_base = ramses_uartd;
+ }
+-
+- isapnp_for_each_dev(dev) {
+- if (dev->active)
+- continue;
+-
+- memset(&board, 0, sizeof(board));
+- board.flags = SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT;
+- board.num_ports = 1;
+- board.base_baud = 115200;
+-
+- for (pnp_board = pnp_devices; pnp_board->vendor; pnp_board++)
+- if ((dev->vendor == pnp_board->vendor) &&
+- (dev->device == pnp_board->device))
+- break;
+-
+- if (pnp_board->vendor) {
+- /* Special case that's more efficient to hardcode */
+- if ((pnp_board->vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
+- pnp_board->device == ISAPNP_DEVICE(0x1021)))
+- board.flags |= SPCI_FL_NO_SHIRQ;
+- } else {
+- if (serial_pnp_guess_board(dev, &board))
+- continue;
+ }
+-
+- if (board.flags & SPCI_FL_NO_SHIRQ)
+- avoid_irq_share(dev);
+- start_pci_pnp_board(dev, &board);
+- }
+-
+-#ifdef SERIAL_DEBUG_PNP
+- printk("Leaving probe_serial_pnp() (probe finished)\n");
+-#endif
+- return;
+-}
+-
+-#endif /* ENABLE_SERIAL_PNP */
+-
+-/*
+- * The serial driver boot-time initialization code!
+- */
+-static int __init rs_init(void)
+-{
+- int i;
+- struct serial_state * state;
+-
+ init_bh(SERIAL_BH, do_serial_bh);
+ init_timer(&serial_timer);
+ serial_timer.function = rs_timer;
+@@ -5463,10 +2723,6 @@
+ for (i = 0; i < NR_IRQS; i++) {
+ IRQ_ports[i] = 0;
+ IRQ_timeout[i] = 0;
+-#ifdef CONFIG_SERIAL_MULTIPORT
+- memset(&rs_multiport[i], 0,
+- sizeof(struct rs_multiport_struct));
+-#endif
+ }
+ #ifdef CONFIG_SERIAL_CONSOLE
+ /*
+@@ -5480,29 +2736,25 @@
+ rs_table[i].irq = 0;
+ }
+ #endif
+- show_serial_version();
+-
+ /* Initialize the tty_driver structure */
+
+ memset(&serial_driver, 0, sizeof(struct tty_driver));
+ serial_driver.magic = TTY_DRIVER_MAGIC;
+-#if (LINUX_VERSION_CODE > 0x20100)
+ serial_driver.driver_name = "serial";
+-#endif
+-#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
++#if defined(CONFIG_DEVFS_FS)
+ serial_driver.name = "tts/%d";
+ #else
+ serial_driver.name = "ttyS";
+ #endif
+ serial_driver.major = TTY_MAJOR;
+- serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
+- serial_driver.name_base = SERIAL_DEV_OFFSET;
++ serial_driver.minor_start = 64;
++ serial_driver.name_base = 0;
+ serial_driver.num = NR_PORTS;
+ serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver.subtype = SERIAL_TYPE_NORMAL;
+ serial_driver.init_termios = tty_std_termios;
+ serial_driver.init_termios.c_cflag =
+- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
++ B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ serial_driver.refcount = &serial_refcount;
+ serial_driver.table = serial_table;
+@@ -5524,31 +2776,25 @@
+ serial_driver.stop = rs_stop;
+ serial_driver.start = rs_start;
+ serial_driver.hangup = rs_hangup;
+-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+ serial_driver.break_ctl = rs_break;
+-#endif
+-#if (LINUX_VERSION_CODE >= 131343)
+ serial_driver.send_xchar = rs_send_xchar;
+ serial_driver.wait_until_sent = rs_wait_until_sent;
+ serial_driver.read_proc = rs_read_proc;
+-#endif
+
+ /*
+ * The callout device is just like normal device except for
+ * major number and the subtype code.
+ */
+ callout_driver = serial_driver;
+-#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
++#if defined(CONFIG_DEVFS_FS)
+ callout_driver.name = "cua/%d";
+ #else
+ callout_driver.name = "cua";
+ #endif
+ callout_driver.major = TTYAUX_MAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+-#if (LINUX_VERSION_CODE >= 131343)
+ callout_driver.read_proc = 0;
+ callout_driver.proc_entry = 0;
+-#endif
+
+ if (tty_register_driver(&serial_driver))
+ panic("Couldn't register serial driver\n");
+@@ -5569,53 +2815,23 @@
+ state->icount.frame = state->icount.parity = 0;
+ state->icount.overrun = state->icount.brk = 0;
+ state->irq = irq_cannonicalize(state->irq);
+- if (state->hub6)
+- state->io_type = SERIAL_IO_HUB6;
+ 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) {
+- state->type = PORT_UNKNOWN;
+- autoconfig(state);
+- }
+ }
+ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+ if (state->type == PORT_UNKNOWN)
+ continue;
+- if ( (state->flags & ASYNC_BOOT_AUTOCONF)
+- && (state->flags & ASYNC_AUTO_IRQ)
+- && (state->port != 0 || state->iomem_base != 0))
+- state->irq = detect_uart_irq(state);
+- if (state->io_type == SERIAL_IO_MEM) {
+- printk(KERN_INFO"ttyS%02d%s at 0x%p (irq = %d) is a %s\n",
+- state->line + SERIAL_DEV_OFFSET,
+- (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
+- state->iomem_base, state->irq,
+- uart_config[state->type].name);
+- }
+- else {
+- printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n",
+- state->line + SERIAL_DEV_OFFSET,
+- (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
+- state->port, state->irq,
++ printk(KERN_INFO"tts/%d at irq %d is a %s\n",
++ state->line,
++ state->irq,
+ uart_config[state->type].name);
+- }
+ tty_register_devfs(&serial_driver, 0,
+ serial_driver.minor_start + state->line);
+ tty_register_devfs(&callout_driver, 0,
+ callout_driver.minor_start + state->line);
+ }
+-#ifdef ENABLE_SERIAL_PCI
+- probe_serial_pci();
+-#endif
+-#ifdef ENABLE_SERIAL_PNP
+- probe_serial_pnp();
+-#endif
+ return 0;
+ }
+
+@@ -5627,6 +2843,8 @@
+ {
+ int i = req->line;
+
++ printk("%s\n", __FUNCTION__);
++
+ if (i >= NR_IRQS)
+ return(-ENOENT);
+ rs_table[i].magic = 0;
+@@ -5639,7 +2857,6 @@
+ rs_table[i].flags = req->flags;
+ rs_table[i].close_delay = req->close_delay;
+ rs_table[i].io_type = req->io_type;
+- rs_table[i].hub6 = req->hub6;
+ rs_table[i].iomem_base = req->iomem_base;
+ rs_table[i].iomem_reg_shift = req->iomem_reg_shift;
+ rs_table[i].type = req->type;
+@@ -5726,7 +2943,6 @@
+ info->iomem_base = req->iomem_base;
+ info->iomem_reg_shift = req->iomem_reg_shift;
+ }
+- autoconfig(state);
+ if (state->type == PORT_UNKNOWN) {
+ restore_flags(flags);
+ printk("register_serial(): autoconfig failed\n");
+@@ -5734,11 +2950,8 @@
+ }
+ restore_flags(flags);
+
+- if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state))
+- state->irq = detect_uart_irq(state);
+-
+ printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
+- state->line + SERIAL_DEV_OFFSET,
++ state->line,
+ state->iomem_base ? "iomem" : "port",
+ state->iomem_base ? (unsigned long)state->iomem_base :
+ state->port, state->irq, uart_config[state->type].name);
+@@ -5746,7 +2959,7 @@
+ serial_driver.minor_start + state->line);
+ tty_register_devfs(&callout_driver, 0,
+ callout_driver.minor_start + state->line);
+- return state->line + SERIAL_DEV_OFFSET;
++ return state->line;
+ }
+
+ /**
+@@ -5785,7 +2998,6 @@
+ int i;
+ struct async_struct *info;
+
+- /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
+ del_timer_sync(&serial_timer);
+ save_flags(flags); cli();
+ remove_bh(SERIAL_BH);
+@@ -5803,41 +3015,31 @@
+ kfree(info);
+ }
+ if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) {
+-#ifdef CONFIG_SERIAL_RSA
+- if (rs_table[i].type == PORT_RSA)
+- release_region(rs_table[i].port +
+- UART_RSA_BASE, 16);
+- else
+-#endif
+ release_region(rs_table[i].port, 8);
+ }
+-#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
+- if (rs_table[i].iomem_base)
+- iounmap(rs_table[i].iomem_base);
+-#endif
+- }
+-#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
+- for (i=0; i < NR_PCI_BOARDS; i++) {
+- struct pci_board_inst *brd = &serial_pci_board[i];
+-
+- if (serial_pci_board[i].dev == 0)
+- continue;
+- if (brd->board.init_fn)
+- (brd->board.init_fn)(brd->dev, &brd->board, 0);
+- if (DEACTIVATE_FUNC(brd->dev))
+- (DEACTIVATE_FUNC(brd->dev))(brd->dev);
+ }
+-#endif
+ if (tmp_buf) {
+ unsigned long pg = (unsigned long) tmp_buf;
+ tmp_buf = NULL;
+ free_page(pg);
+ }
+
+-#ifdef ENABLE_SERIAL_PCI
+- if (serial_pci_driver.name[0])
+- pci_unregister_driver (&serial_pci_driver);
+-#endif
++ if (ramses_uarta) {
++ iounmap(ramses_uarta);
++ release_mem_region(RAMSES_UARTA_PHYS, 16*4);
++ }
++ if (ramses_uartb) {
++ iounmap(ramses_uartb);
++ release_mem_region(RAMSES_UARTB_PHYS, 16*4);
++ }
++ if (ramses_uartc) {
++ iounmap(ramses_uartc);
++ release_mem_region(RAMSES_UARTC_PHYS, 16*4);
++ }
++ if (ramses_uartd) {
++ iounmap(ramses_uartd);
++ release_mem_region(RAMSES_UARTD_PHYS, 16*4);
++ }
+ }
+
+ module_init(rs_init);
+@@ -5946,7 +3148,7 @@
+ static struct async_struct *info;
+ struct serial_state *state;
+ unsigned cval;
+- int baud = 9600;
++ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int doflow = 0;
+@@ -5954,6 +3156,8 @@
+ int quot = 0;
+ char *s;
+
++ printk("%s\n", __FUNCTION__);
++
+ if (options) {
+ baud = simple_strtoul(options, NULL, 10);
+ s = options;
+@@ -6028,19 +3232,12 @@
+ info->state = state;
+ info->port = state->port;
+ info->flags = state->flags;
+-#ifdef CONFIG_HUB6
+- info->hub6 = state->hub6;
+-#endif
+ info->io_type = state->io_type;
+ info->iomem_base = state->iomem_base;
+ info->iomem_reg_shift = state->iomem_reg_shift;
+ quot = state->baud_base / baud;
+ cval = cflag & (CSIZE | CSTOPB);
+-#if defined(__powerpc__) || defined(__alpha__)
+- cval >>= 8;
+-#else /* !__powerpc__ && !__alpha__ */
+ cval >>= 4;
+-#endif /* !__powerpc__ && !__alpha__ */
+ if (cflag & PARENB)
+ cval |= UART_LCR_PARITY;
+ if (!(cflag & PARODD))
+@@ -6082,9 +3279,14 @@
+ */
+ void __init serial_console_init(void)
+ {
++ printk("%s\n", __FUNCTION__);
++
+ register_console(&sercons);
+ }
+ #endif
++
++EXPORT_SYMBOL(register_serial);
++EXPORT_SYMBOL(unregister_serial);
+
+ /*
+ Local variables:
+--- /dev/null
++++ linux-2.4.21/drivers/char/sysctl.c
+@@ -0,0 +1,948 @@
++/*
++ * /proc/sys-board - Interface to the 16 bit latch and other
++ * ramses-related hardware settings
++ *
++ * (C) 2002,2003 by M&N Logistik-Lösungen Online GmbH
++ * written by H.Schurig
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/sysctl.h>
++#include <linux/crc32.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++
++#include <asm/io.h>
++#include <asm/arch/ramses.h>
++#include <asm/uaccess.h>
++
++#include "../drivers/misc/ucb1x00.h"
++
++//#define DEBUG
++//define CPLD_LED 1
++//define POTI 1
++
++/*
++ * This is the number for the "board" entry in /proc/sys:
++ */
++#define RAMSES_SYSCTL 1312
++
++/*
++ * These are the numbers for the entries in /etc/sys/board
++ */
++enum {
++ CTL_NAME=991,
++ CTL_CPLD_VERSION,
++ CTL_BOOTLOADER_CRC,
++ CTL_LINUX_CRC,
++ CTL_LED_BLUE,
++ CTL_LED_ORANGE,
++ CTL_UART,
++ CTL_MMC,
++ CTL_POWEROFF,
++ CTL_GSM_POWER,
++ CTL_GSM_RESET,
++ CTL_SCANNER_POWER,
++ CTL_SCANNER_WAKE,
++ CTL_SCANNER_TRIG,
++ CTL_SCANNER_BEAM,
++ CTL_KEY_SCAN,
++ CTL_KEY_SUSPEND,
++ CTL_KEY_OFF,
++ CTL_USBBUS_POWER,
++ CTL_USBCHIP_POWER,
++#ifdef CPLD_LED
++ CTL_LED_CPLD,
++ CTL_LED_CPLD_RED,
++#endif
++ CTL_LCD_VCC,
++ CTL_LCD_DISPOFF,
++ CTL_LCD_BLIGHT,
++#ifdef DEBUG
++ CTL_LCD_PWM0,
++ CTL_LCD_PWM1,
++#endif
++ CTL_LCD_BRIGHTNESS,
++ CTL_LCD_CONTRAST,
++ CTL_LCD_FBTURN,
++ CTL_LCD_TYPE,
++ CTL_CONTROL_SHADOW,
++ CTL_COREVOLT,
++#ifdef POTI
++ CTL_LCD_POTI_NINC,
++ CTL_LCD_POTI_NCS,
++ CTL_LCD_POTI_UP,
++#endif
++#ifdef CONFIG_MCP_UCB1400_TS
++ CTL_ADC0,
++ CTL_ADC1,
++ CTL_ADC2,
++ CTL_ADC3,
++#else
++#error NO UCB
++#endif
++ CTL_CHG_STS,
++ CTL_WALL_IN,
++ CTL_BATT_TMP,
++ CTL_BATT_LMD,
++ CTL_BATT_VSB,
++ CTL_BATT_RCAC,
++ CTL_BATT_CACT,
++ CTL_BATT_SAE,
++ CTL_BATT_DCR,
++};
++
++static const char ramses_board_name[] = "ramses";
++static int dummy_int = 0;
++static char dummy_str[80];
++
++
++
++/******************************************************************/
++/* ADC communication */
++/******************************************************************/
++
++
++#ifdef CONFIG_MCP_UCB1400_TS
++static int adc_get(int channel)
++{
++ int val;
++ struct ucb1x00 *ucb = ucb1x00_get();
++
++ ucb1x00_adc_enable(ucb);
++ val = ucb1x00_adc_read(ucb, channel, 0);
++ ucb1x00_adc_disable(ucb);
++
++ return val;
++}
++#endif
++
++
++
++static int
++ramses_sysctl_handler(ctl_table * ctl, int write, struct file *filp,
++ void *buffer, size_t * lenp)
++{
++ int *valp = ctl->data;
++ int val;
++ int ret;
++ unsigned crc;
++ void *flash;
++
++#ifdef DEBUG
++ printk("ramses_control_shadow: %04x\n", ramses_control_shadow);
++#endif
++
++ // Update parameters from the real registers
++ switch (ctl->ctl_name) {
++ case CTL_CPLD_VERSION:
++ sprintf(dummy_str,"20%02ld-%02ld-%02ld.%ld\n",
++ RAMSES_CPLD_YEAR & 0xff,
++ RAMSES_CPLD_MONTH & 0xff,
++ RAMSES_CPLD_DAY & 0xff,
++ RAMSES_CPLD_REV & 0xff);
++ return proc_dostring(ctl,write,filp,buffer,lenp);
++
++ case CTL_BOOTLOADER_CRC:
++ flash = ioremap_nocache(RAMSES_FLASH_PHYS, 0x40000);
++ crc = ether_crc_le(0x40000, flash);
++ iounmap(flash);
++ sprintf(dummy_str,"%08x", crc);
++ return proc_dostring(ctl,write,filp,buffer,lenp);
++
++ case CTL_LINUX_CRC:
++ flash = ioremap_nocache(RAMSES_FLASH_PHYS+0x40000, 3*0x40000);
++ crc = ether_crc_le(3*0x40000, flash);
++ iounmap(flash);
++ sprintf(dummy_str,"%08x", crc);
++ return proc_dostring(ctl,write,filp,buffer,lenp);
++
++ case CTL_LED_BLUE:
++ *valp = (ramses_control_shadow & RAMSES_CONTROL_LED_BLUE_) == 0;
++ break;
++ case CTL_LED_ORANGE:
++ *valp = (ramses_control_shadow & RAMSES_CONTROL_LED_ORANGE_) == 0;
++ break;
++ case CTL_UART:
++ *valp = (ramses_control_shadow & RAMSES_CONTROL_UART_PWR) != 0;
++ break;
++ case CTL_MMC:
++ *valp = (ramses_control_shadow & RAMSES_CONTROL_MMC_PWR) != 0;
++ break;
++ case CTL_POWEROFF:
++ *valp = 0;
++ break;
++ case CTL_GSM_POWER:
++ *valp = (ramses_control_shadow & RAMSES_CONTROL_GSM_PWR) != 0;
++ break;
++ case CTL_GSM_RESET:
++ *valp = (ramses_control_shadow & RAMSES_CONTROL_GSM_RESET) != 0;
++ break;
++
++ case CTL_SCANNER_POWER:
++ *valp = (ramses_control_shadow & RAMSES_CONTROL_SCANNER_PWR) != 0;
++ break;
++ case CTL_SCANNER_WAKE:
++ *valp = (ramses_control_shadow & RAMSES_CONTROL_SCANNER_WAKE_) == 0;
++ break;
++ case CTL_SCANNER_TRIG:
++ *valp = (ramses_control_shadow & RAMSES_CONTROL_SCANNER_TRIG_) == 0;
++ break;
++ case CTL_SCANNER_BEAM:
++ *valp = ramses_flags & RAMSES_FLAGS_SCANNER_BEAM;
++ break;
++
++ case CTL_KEY_SCAN:
++ *valp = (ramses_flags & RAMSES_FLAGS_KEY_SCAN) != 0;
++ break;
++ case CTL_KEY_SUSPEND:
++ *valp = (ramses_flags & RAMSES_FLAGS_KEY_SUSPEND) != 0;
++ break;
++ case CTL_KEY_OFF:
++ *valp = (ramses_flags & RAMSES_FLAGS_KEY_OFF) != 0;
++ break;
++
++ case CTL_USBBUS_POWER:
++ *valp = (ramses_control_shadow & RAMSES_CONTROL_USB) != 0;
++ break;
++ case CTL_USBCHIP_POWER:
++ *valp = (RAMSES_CPLD_PERIPH_PWR & USB_HOST_PWR_EN) != 0;
++ break;
++#ifdef CPLD_LED
++ case CTL_LED_CPLD:
++ *valp = (RAMSES_CPLD_LED_CONTROL & CPLD_LED1) == 0;
++ break;
++ case CTL_LED_CPLD_RED:
++ *valp = (RAMSES_CPLD_LED_CONTROL & CPLD_LED2) == 0;
++ break;
++#endif
++ case CTL_LCD_BLIGHT:
++ *valp = (ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT) != 0;
++ break;
++ case CTL_LCD_VCC:
++ *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_VCC) != 0;
++ break;
++ case CTL_LCD_DISPOFF:
++ *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_DISPOFF) != 0;
++ break;
++#ifdef DEBUG
++ case CTL_LCD_PWM0:
++ *valp = PWM_PWDUTY0;
++ break;
++ case CTL_LCD_PWM1:
++#ifdef OLDCODE
++ *valp = ramses_lcd_pwm1_shadow;
++#else
++ *valp = PWM_PWDUTY1;
++#endif
++ break;
++#endif
++ case CTL_LCD_BRIGHTNESS:
++ *valp = ramses_lcd_get_brightness();
++ break;
++ case CTL_LCD_CONTRAST:
++ *valp = ramses_lcd_get_contrast();
++ break;
++ case CTL_LCD_FBTURN:
++ *valp = (ramses_flags & RAMSES_FLAGS_LCD_FBTURN) != 0;
++ break;
++ case CTL_LCD_TYPE:
++ *valp = ramses_lcd_type;
++ break;
++
++ case CTL_CONTROL_SHADOW:
++ sprintf(dummy_str,"%04x", ramses_control_shadow);
++ return proc_dostring(ctl,write,filp,buffer,lenp);
++
++ case CTL_COREVOLT:
++ *valp = ramses_corevolt_shadow;
++ break;
++
++#ifdef POTI
++ case CTL_LCD_POTI_NINC:
++ *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_PINC) != 0;
++ break;
++ case CTL_LCD_POTI_NCS:
++ *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_PCS) != 0;
++ break;
++ case CTL_LCD_POTI_UP:
++ *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_PUP) != 0;
++ break;
++#endif
++
++#ifdef CONFIG_MCP_UCB1400_TS
++ case CTL_ADC0:
++ *valp = adc_get(UCB_ADC_INP_AD0);
++ break;
++ case CTL_ADC1:
++ *valp = adc_get(UCB_ADC_INP_AD1);
++ break;
++ case CTL_ADC2:
++ *valp = adc_get(UCB_ADC_INP_AD2);
++ break;
++ case CTL_ADC3:
++ *valp = adc_get(UCB_ADC_INP_AD3);
++ break;
++#endif
++
++ case CTL_CHG_STS:
++ *valp = (RAMSES_CPLD_MISC_STATUS & RAMSES_CHG_STS) == 0;
++ break;
++ case CTL_WALL_IN:
++ *valp = (RAMSES_CPLD_MISC_STATUS & RAMSES_WALL_IN) != 0;
++ break;
++
++ case CTL_BATT_TMP:
++ *valp = ramses_hdq_get_reg(HDQ_TMP) >> 4;
++ break;
++ case CTL_BATT_LMD:
++ *valp = ramses_hdq_get_reg(HDQ_LMD);
++ break;
++ case CTL_BATT_VSB:
++ *valp = ramses_hdq_get_reg(HDQ_VSB);
++ break;
++ case CTL_BATT_RCAC:
++ *valp = ramses_hdq_get_reg(HDQ_RCAC) & 0x7f;
++ break;
++ case CTL_BATT_CACT:
++ *valp = ramses_hdq_get_reg(HDQ_CACT);
++ break;
++ case CTL_BATT_SAE:
++ *valp = ramses_hdq_get_reg(HDQ_SAEH) << 8 | ramses_hdq_get_reg(HDQ_SAEL);
++ break;
++ case CTL_BATT_DCR:
++ *valp = ramses_hdq_get_reg(HDQ_DCR);
++ break;
++
++ default:
++ // Just ignore unsupported parameters
++ break;
++ }
++
++ // Save old state
++ val = *valp;
++
++ // Perform the generic integer operation
++ if ((ret = proc_dointvec(ctl, write, filp, buffer, lenp)) != 0)
++ return (ret);
++
++ // Write changes out to the registers
++ if (write && *valp != val) {
++
++ val = *valp;
++ switch (ctl->ctl_name) {
++
++ case CTL_LED_BLUE:
++ if (val)
++ RAMSES_LED_BLUE_ON()
++ else
++ RAMSES_LED_BLUE_OFF();
++ break;
++
++ case CTL_LED_ORANGE:
++ if (val)
++ RAMSES_LED_ORANGE_ON()
++ else
++ RAMSES_LED_ORANGE_OFF();
++ break;
++
++ case CTL_UART:
++ if (val)
++ RAMSES_UART_ON()
++ else
++ RAMSES_UART_OFF();
++ break;
++
++ case CTL_MMC:
++ if (val)
++ RAMSES_MMC_ON()
++ else
++ RAMSES_MMC_OFF();
++ break;
++
++ case CTL_POWEROFF:
++ if (val)
++ pm_power_off();
++ break;
++
++ case CTL_GSM_POWER:
++ if (val)
++ RAMSES_GSM_ON()
++ else
++ RAMSES_GSM_OFF();
++ break;
++
++ case CTL_GSM_RESET:
++ if (val)
++ RAMSES_GSM_RESET_ON()
++ else
++ RAMSES_GSM_RESET_OFF();
++ break;
++
++ case CTL_SCANNER_POWER:
++ if (val)
++ RAMSES_SCANNER_ON()
++ else
++ RAMSES_SCANNER_OFF();
++ break;
++
++ case CTL_SCANNER_WAKE:
++ if (val)
++ RAMSES_SCANNER_WAKE_ON()
++ else
++ RAMSES_SCANNER_WAKE_OFF();
++ break;
++
++ case CTL_SCANNER_TRIG:
++ if (val)
++ RAMSES_SCANNER_TRIG_ON()
++ else
++ RAMSES_SCANNER_TRIG_OFF();
++ break;
++
++ case CTL_SCANNER_BEAM:
++ if (val)
++ ramses_flags |= RAMSES_FLAGS_SCANNER_BEAM;
++ else
++ ramses_flags &= ~RAMSES_FLAGS_SCANNER_BEAM;
++ break;
++
++ case CTL_KEY_SCAN:
++ if (val)
++ ramses_flags |= RAMSES_FLAGS_KEY_SCAN;
++ else
++ ramses_flags &= ~RAMSES_FLAGS_KEY_SCAN;
++ break;
++
++ case CTL_KEY_SUSPEND:
++ if (val)
++ ramses_flags |= RAMSES_FLAGS_KEY_SUSPEND;
++ else
++ ramses_flags &= ~RAMSES_FLAGS_KEY_SUSPEND;
++ break;
++
++ case CTL_KEY_OFF:
++ if (val)
++ ramses_flags |= RAMSES_FLAGS_KEY_OFF;
++ else
++ ramses_flags &= ~RAMSES_FLAGS_KEY_OFF;
++ break;
++
++ case CTL_USBBUS_POWER:
++ if (val)
++ RAMSES_USB_BUS_ON()
++ else
++ RAMSES_USB_BUS_OFF();
++ break;
++
++ case CTL_USBCHIP_POWER:
++ if (val)
++ RAMSES_CPLD_PERIPH_PWR |= USB_HOST_PWR_EN;
++ else
++ RAMSES_CPLD_PERIPH_PWR &= ~USB_HOST_PWR_EN;
++ break;
++
++#ifdef CPLD_LED
++ case CTL_LED_CPLD:
++ if (val)
++ RAMSES_CPLD_LED_CONTROL &= ~CPLD_LED1;
++ else
++ RAMSES_CPLD_LED_CONTROL |= CPLD_LED1;
++ break;
++
++ case CTL_LED_CPLD_RED:
++ if (val)
++ RAMSES_CPLD_LED_CONTROL &= ~CPLD_LED2;
++ else
++ RAMSES_CPLD_LED_CONTROL |= CPLD_LED2;
++ break;
++#endif
++
++ case CTL_LCD_BLIGHT:
++ if (val)
++ ramses_lcd_backlight_on();
++ else
++ ramses_lcd_backlight_off();
++ break;
++
++ case CTL_LCD_VCC:
++ if (val)
++ RAMSES_CPLD_LCD |= RAMSES_LCD_VCC;
++ else
++ RAMSES_CPLD_LCD &= ~RAMSES_LCD_VCC;
++ break;
++
++ case CTL_LCD_DISPOFF:
++ if (val)
++ RAMSES_CPLD_LCD |= RAMSES_LCD_DISPOFF;
++ else
++ RAMSES_CPLD_LCD &= ~RAMSES_LCD_DISPOFF;
++ break;
++
++#ifdef DEBUG
++ case CTL_LCD_PWM0:
++ PWM_PWDUTY0 = val;
++ break;
++
++ case CTL_LCD_PWM1:
++#ifdef OLDCODE
++ ramses_lcd_set_pwm1(val);
++#else
++ PWM_PWDUTY1 = val;
++#endif
++ break;
++#endif
++
++ case CTL_LCD_BRIGHTNESS:
++ ramses_lcd_set_brightness(val);
++ break;
++
++ case CTL_LCD_CONTRAST:
++ ramses_lcd_set_contrast(val);
++ break;
++
++ case CTL_LCD_FBTURN:
++ if (val)
++ ramses_flags |= RAMSES_FLAGS_LCD_FBTURN;
++ else
++ ramses_flags &= ~RAMSES_FLAGS_LCD_FBTURN;
++ break;
++
++ case CTL_COREVOLT:
++ ramses_set_corevolt(val);
++ break;
++
++#ifdef POTI
++ case CTL_LCD_POTI_NCS:
++ if (val)
++ RAMSES_CPLD_LCD |= RAMSES_LCD_PCS;
++ else
++ RAMSES_CPLD_LCD &= ~RAMSES_LCD_PCS;
++ break;
++ case CTL_LCD_POTI_NINC:
++ if (val)
++ RAMSES_CPLD_LCD |= RAMSES_LCD_PINC;
++ else
++ RAMSES_CPLD_LCD &= ~RAMSES_LCD_PINC;
++ break;
++ case CTL_LCD_POTI_UP:
++ if (val)
++ RAMSES_CPLD_LCD |= RAMSES_LCD_PUP;
++ else
++ RAMSES_CPLD_LCD &= ~RAMSES_LCD_PUP;
++ break;
++#endif
++
++ default:
++ // Just ignore unsupported parameters
++ break;
++ }
++ }
++
++#ifdef DEBUG
++ printk("ramses_control_shadow new: %04x\n", ramses_control_shadow);
++#endif
++ return ret;
++}
++
++
++
++static ctl_table ramses_table[] = {
++ {
++ procname: "sys_name",
++ ctl_name: CTL_NAME,
++ data: &ramses_board_name,
++ maxlen: sizeof(ramses_board_name),
++ proc_handler: &proc_dostring,
++ mode: 0444, // read-only
++ }, {
++ procname: "sys_cpldver",
++ ctl_name: CTL_CPLD_VERSION,
++ data: &dummy_str,
++ maxlen: sizeof(dummy_str),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444, // read-only
++ }, {
++ procname: "sys_bootcrc",
++ ctl_name: CTL_BOOTLOADER_CRC,
++ data: &dummy_str,
++ maxlen: sizeof(dummy_str),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444, // read-only
++ }, {
++ procname: "sys_linuxcrc",
++ ctl_name: CTL_LINUX_CRC,
++ data: &dummy_str,
++ maxlen: sizeof(dummy_str),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444, // read-only
++ }, {
++ procname: "led_blue",
++ ctl_name: CTL_LED_BLUE,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "led_orange",
++ ctl_name: CTL_LED_ORANGE,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "pwr_uart",
++ ctl_name: CTL_UART,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "pwr_mmc",
++ ctl_name: CTL_MMC,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "pwr_off",
++ ctl_name: CTL_POWEROFF,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "gsm_power",
++ ctl_name: CTL_GSM_POWER,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "gsm_reset",
++ ctl_name: CTL_GSM_RESET,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "scanner_power",
++ ctl_name: CTL_SCANNER_POWER,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "scanner_wake",
++ ctl_name: CTL_SCANNER_WAKE,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "scanner_trig",
++ ctl_name: CTL_SCANNER_TRIG,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "scanner_beam",
++ ctl_name: CTL_SCANNER_BEAM,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "key_scan",
++ ctl_name: CTL_KEY_SCAN,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "key_suspend",
++ ctl_name: CTL_KEY_SUSPEND,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "key_off",
++ ctl_name: CTL_KEY_OFF,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "usb_bus_power",
++ ctl_name: CTL_USBBUS_POWER,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "usb_chip_power",
++ ctl_name: CTL_USBCHIP_POWER,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ },
++#if LED_CPLD
++ {
++ procname: "led_cpld",
++ ctl_name: CTL_LED_CPLD,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "led_cpld_red",
++ ctl_name: CTL_LED_CPLD_RED,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ },
++#endif
++ {
++ procname: "lcd_backlight",
++ ctl_name: CTL_LCD_BLIGHT,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "lcd_vcc",
++ ctl_name: CTL_LCD_VCC,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "lcd_dispoff",
++ ctl_name: CTL_LCD_DISPOFF,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "lcd_brightness",
++ ctl_name: CTL_LCD_BRIGHTNESS,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "lcd_contrast",
++ ctl_name: CTL_LCD_CONTRAST,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "lcd_fbturn",
++ ctl_name: CTL_LCD_FBTURN,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "lcd_type",
++ ctl_name: CTL_LCD_TYPE,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ },
++#ifdef POTI
++ {
++ procname: "lcd_poti_ncs",
++ ctl_name: CTL_LCD_POTI_NCS,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "lcd_poti_ninc",
++ ctl_name: CTL_LCD_POTI_NINC,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "lcd_poti_up",
++ ctl_name: CTL_LCD_POTI_UP,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ },
++#endif
++#ifdef DEBUG
++ {
++ procname: "lcd_pwm0",
++ ctl_name: CTL_LCD_PWM0,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ }, {
++ procname: "lcd_pwm1",
++ ctl_name: CTL_LCD_PWM1,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ },
++#endif
++ {
++ procname: "sys_shadowreg",
++ ctl_name: CTL_CONTROL_SHADOW,
++ data: &dummy_str,
++ maxlen: sizeof(dummy_str),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ },
++ {
++ procname: "pwr_corevolt",
++ ctl_name: CTL_COREVOLT,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0664,
++ },
++#ifdef CONFIG_MCP_UCB1400_TS
++ {
++ procname: "adc0_vcc",
++ ctl_name: CTL_ADC0,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ }, {
++ procname: "adc1_ntc",
++ ctl_name: CTL_ADC1,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ }, {
++ procname: "adc2_goldcap",
++ ctl_name: CTL_ADC2,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ }, {
++ procname: "adc3_batt",
++ ctl_name: CTL_ADC3,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ },
++#else
++#error No UCB
++#endif
++ {
++ procname: "pwr_wall_in",
++ ctl_name: CTL_WALL_IN,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ }, {
++ procname: "batt_charge",
++ ctl_name: CTL_CHG_STS,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ }, {
++ procname: "batt_temp",
++ ctl_name: CTL_BATT_TMP,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ }, {
++ procname: "batt_lmd",
++ ctl_name: CTL_BATT_LMD,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ }, {
++ procname: "batt_vsb",
++ ctl_name: CTL_BATT_VSB,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ }, {
++ procname: "batt_rcac",
++ ctl_name: CTL_BATT_RCAC,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ }, {
++ procname: "batt_cact",
++ ctl_name: CTL_BATT_CACT,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ }, {
++ procname: "batt_sae",
++ ctl_name: CTL_BATT_SAE,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ }, {
++ procname: "batt_dcr",
++ ctl_name: CTL_BATT_DCR,
++ data: &dummy_int,
++ maxlen: sizeof(int),
++ proc_handler: &ramses_sysctl_handler,
++ mode: 0444,
++ },
++
++ {0}
++ };
++
++static ctl_table ramses_root_table[] = {
++ {RAMSES_SYSCTL, "board", NULL, 0, 0555, ramses_table},
++ {0}
++ };
++
++
++static struct ctl_table_header *ramses_table_header;
++
++
++static int __init ramses_sysctl_init(void)
++{
++ ramses_table_header = register_sysctl_table(ramses_root_table, 0);
++ if (!ramses_table_header)
++ return -ENOMEM;
++ return 0;
++}
++
++static void __exit ramses_sysctl_exit(void)
++{
++ unregister_sysctl_table(ramses_table_header);
++}
++
++
++module_init(ramses_sysctl_init);
++module_exit(ramses_sysctl_exit);
++
++MODULE_AUTHOR("Holger Schurig <h.schurig@mn-logistik.de>");
++MODULE_DESCRIPTION("Implements /proc/sys/board");
++MODULE_LICENSE("GPL");
+--- linux-2.4.21/drivers/char/vt.c~linux-vtcomparison
++++ linux-2.4.21/drivers/char/vt.c
+@@ -163,7 +163,9 @@
+
+ if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
+ return -EFAULT;
+- if (i >= NR_KEYS || s >= MAX_NR_KEYMAPS)
++ if (i >= NR_KEYS)
++ return -EINVAL;
++ if (s >= MAX_NR_KEYMAPS)
+ return -EINVAL;
+
+ switch (cmd) {
+--- linux-2.4.21/drivers/input/Config.in~keyb-input
++++ linux-2.4.21/drivers/input/Config.in
+@@ -7,6 +7,8 @@
+
+ tristate 'Input core support' CONFIG_INPUT
+ dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
++dep_tristate ' Ramses keyboard' CONFIG_INPUT_RAMSES_KEYB $CONFIG_INPUT_KEYBDEV $CONFIG_ARCH_RAMSES
++dep_tristate ' Ramses wedge' CONFIG_INPUT_RAMSES_WEDGE $CONFIG_INPUT_RAMSES_KEYB
+ dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
+ if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
+ int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
+--- linux-2.4.21/drivers/input/Makefile~ramses-keyb
++++ linux-2.4.21/drivers/input/Makefile
+@@ -8,7 +8,7 @@
+
+ # Objects that export symbols.
+
+-export-objs := input.o
++export-objs := input.o ramses_keyb.o
+
+ # Object file lists.
+
+@@ -21,10 +21,12 @@
+
+ obj-$(CONFIG_INPUT) += input.o
+ obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o
++obj-$(CONFIG_INPUT_RAMSES_KEYB) += ramses_keyb.o
+ 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_RAMSES_WEDGE) += wedge.o
+
+ # The global Rules.make.
+
+--- /dev/null
++++ linux-2.4.21/drivers/input/ramses_cellmap.h
+@@ -0,0 +1,34 @@
++static int ramses_cellmap[][8] = {
++ { KEY_A, KEY_B, KEY_C, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 0
++ { KEY_D, KEY_E, KEY_F, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 1
++ { KEY_G, KEY_H, KEY_I, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 2
++ { KEY_J, KEY_K, KEY_L, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 3
++ { KEY_M, KEY_N, KEY_O, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 4
++ { KEY_P, KEY_Q, KEY_R, KEY_S, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 5
++ { KEY_T, KEY_U, KEY_V, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 6
++ { KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 7
++ { KEY_AE, KEY_OE, KEY_UE, KEY_SZ, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 8
++ { KEY_sA, KEY_sB, KEY_sC, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 9
++ { KEY_sD, KEY_sE, KEY_sF, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 10
++ { KEY_sG, KEY_sH, KEY_sI, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 11
++ { KEY_sJ, KEY_sK, KEY_sL, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 12
++ { KEY_sM, KEY_sN, KEY_sO, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 13
++ { KEY_sP, KEY_sQ, KEY_sR, KEY_sS, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 14
++ { KEY_sT, KEY_sU, KEY_sV, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 15
++ { KEY_sW, KEY_sX, KEY_sY, KEY_sZ, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 16
++ { KEY_sAE, KEY_sOE, KEY_sUE, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 17
++ { KEY_COLON, KEY_FSLASH,KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 18
++ { KEY_SEMI, KEY_BSLASH,KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 19
++ { KEY_COMMA, KEY_STAR, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 20
++ { KEY_UNDERL,KEY_EQUAL, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 21
++ { KEY_PLUS, KEY_MINUS, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 22
++ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 24
++ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 24
++ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 25
++ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 26
++ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 27
++ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 28
++ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 29
++ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 30
++ { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 31
++};
+--- /dev/null
++++ linux-2.4.21/drivers/input/ramses_keyb.c
+@@ -0,0 +1,596 @@
++/*
++ * Keyboard driver using input layer
++ *
++ * (C) 2002,2003 by M&N Logistik-Lösungen Online GmbH
++ * written by H.Schurig
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/input.h>
++#include <linux/delay.h>
++
++#include <asm/keyboard.h>
++#include <asm/irq.h>
++#include <linux/keyboard.h>
++
++// Debug
++//#define DEBUG
++//#define DEBUG_DUMP_KEYSTATE
++#ifdef DEBUG
++# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
++# define PRINTK(fmt, args...) printk(fmt, ## args)
++#else
++# define DPRINTK(fmt, args...)
++# define PRINTK(fmt, args...)
++#endif
++
++
++/*
++ * Timeouts
++ */
++#define SCANINTERVAL HZ/10
++#define TRIGOFFINTERVAL HZ*2
++#define CELLINTERVAL HZ+HZ/2
++#define MAPINTERVAL 15*HZ
++#define SUSPEND_COUNTER 40
++#define SUSPEND_LED_COUNTER 8
++#define SUSPEND_NOW 0xffff
++#define KEYBD_MATRIX_SETTLING_TIME_US 100
++
++
++/*
++ * macros for matrix keyboard driver
++ */
++#define KEYBD_MATRIX_NUMBER_INPUTS 7
++#define KEYBD_MATRIX_NUMBER_OUTPUTS 14
++
++#define KEYBD_MATRIX_SET_OUTPUTS(outputs) \
++{\
++ RAMSES_CPLD_KB_COL_LOW = outputs;\
++ RAMSES_CPLD_KB_COL_HIGH = outputs >> 7;\
++}
++
++#define KEYBD_MATRIX_GET_INPUTS(inputs) \
++{\
++ inputs = (RAMSES_CPLD_KB_ROW & 0x7f);\
++}
++
++
++// External functions (are they in some #include file?)
++extern int input_setkeycode(unsigned int scancode, unsigned int keycode);
++extern int input_getkeycode(unsigned int scancode);
++extern int input_translate(unsigned char scancode, unsigned char *keycode,
++ char raw_mode);
++extern char input_unexpected_up(unsigned char keycode);
++extern unsigned char input_sysrq_xlate[];
++extern int pm_suggest_suspend(void);
++
++// Keyboard-Related definitions
++#define KEYBD_MATRIX_INPUT_MASK ((1 << KEYBD_MATRIX_NUMBER_INPUTS)-1)
++#define KEYBD_MATRIX_OUTPUT_MASK ((1 << KEYBD_MATRIX_NUMBER_OUTPUTS)-1)
++
++#include "ramses_scancodes.h"
++#include "ramses_keymap.h"
++#include "ramses_cellmap.h"
++
++
++static char *kbd_name = "Keyboard";
++struct input_dev ramses_kbd_dev;
++static struct timer_list reenable_timer;
++static struct timer_list trigoff_timer;
++static struct tq_struct tq_suspend;
++static __u16 keystate_cur[KEYBD_MATRIX_NUMBER_OUTPUTS];
++static __u16 keystate_prev[KEYBD_MATRIX_NUMBER_OUTPUTS];
++static __u16 keystate_keep[KEYBD_MATRIX_NUMBER_OUTPUTS]; // used for auto-repeat
++static struct timer_list cell_timer;
++static int curr_map = MAP_NORMAL;
++static int cell_key = -1;
++static int cell_sel = -1;
++static struct pm_dev *pm_keyb;
++static int suspend_counter = 0;
++
++
++void ramses_key(int keycode)
++{
++ DPRINTK("keycode: %d 0x%x\n", keycode, keycode);
++ if (KVAL(keycode)) {
++ switch (KMOD(keycode)) {
++ case KM_SHIFT:
++ DPRINTK("shift\n");
++ input_report_key(&ramses_kbd_dev, KEY_LEFTSHIFT, 1);
++ break;
++ case KM_CTRL:
++ DPRINTK("ctrl\n");
++ input_report_key(&ramses_kbd_dev, KEY_LEFTCTRL, 1);
++ break;
++ case KM_ALT:
++ DPRINTK("alt\n");
++ input_report_key(&ramses_kbd_dev, KEY_LEFTALT, 1);
++ break;
++ case KM_ALTGR:
++ DPRINTK("altgr\n");
++ input_report_key(&ramses_kbd_dev, KEY_RIGHTALT, 1);
++ break;
++ case KM_ALTCTRL:
++ DPRINTK("alt+ctrl\n");
++ input_report_key(&ramses_kbd_dev, KEY_LEFTALT, 1);
++ input_report_key(&ramses_kbd_dev, KEY_LEFTCTRL, 1);
++ break;
++ }
++
++ DPRINTK("report: %d 0x%x\n", KVAL(keycode), KVAL(keycode));
++ input_report_key(&ramses_kbd_dev, KVAL(keycode), 1);
++ input_report_key(&ramses_kbd_dev, KVAL(keycode), 0);
++
++ switch (KMOD(keycode)) {
++ case KM_SHIFT:
++ input_report_key(&ramses_kbd_dev, KEY_LEFTSHIFT, 0);
++ break;
++ case KM_CTRL:
++ input_report_key(&ramses_kbd_dev, KEY_LEFTCTRL, 0);
++ break;
++ case KM_ALT:
++ input_report_key(&ramses_kbd_dev, KEY_LEFTALT, 0);
++ break;
++ case KM_ALTGR:
++ input_report_key(&ramses_kbd_dev, KEY_RIGHTALT, 0);
++ break;
++ case KM_ALTCTRL:
++ input_report_key(&ramses_kbd_dev, KEY_LEFTALT, 0);
++ input_report_key(&ramses_kbd_dev, KEY_LEFTCTRL, 0);
++ break;
++ }
++ }
++}
++
++static void kbd_cell_timer(unsigned long keepmap)
++{
++ int keycode;
++
++ if (cell_sel != -1) {
++ keycode = ramses_cellmap[cell_key][cell_sel];
++ //DPRINTK("key: %d sel: %d keycode: %d 0x%x\n", cell_key, cell_sel, keycode, keycode);
++ ramses_key(keycode);
++ cell_sel = -1;
++ }
++
++ if (!keepmap && curr_map!=MAP_NORMAL) {
++ DPRINTK("normal map because of %ld\n", keepmap);
++ curr_map = MAP_NORMAL;
++ RAMSES_LED_BLUE_OFF();
++ RAMSES_LED_ORANGE_OFF();
++ }
++}
++
++static void kbd_setleds(void)
++{
++ if (suspend_counter >= SUSPEND_LED_COUNTER) {
++ if (suspend_counter & 4) {
++ RAMSES_LED_ORANGE_OFF();
++ RAMSES_LED_BLUE_ON();
++ } else {
++ RAMSES_LED_ORANGE_ON();
++ RAMSES_LED_BLUE_OFF();
++ }
++ return;
++ }
++
++ switch (curr_map) {
++ case MAP_NORMAL:
++ RAMSES_LED_BLUE_OFF();
++ RAMSES_LED_ORANGE_OFF();
++ return;
++
++ case MAP_BLUE:
++ RAMSES_LED_BLUE_ON();
++ RAMSES_LED_ORANGE_OFF();
++ return;
++
++ case MAP_ORANGE:
++ RAMSES_LED_BLUE_OFF();
++ RAMSES_LED_ORANGE_ON();
++ return;
++
++ case MAP_CAPS:
++ RAMSES_LED_BLUE_ON();
++ RAMSES_LED_ORANGE_ON();
++ return;
++ }
++ DPRINTK("unknown map\n");
++}
++
++
++static void kbd_start_scanner(void)
++{
++ RAMSES_SCANNER_TRIG_OFF();
++ RAMSES_SCANNER_WAKE_OFF();
++ RAMSES_SCANNER_TRIG_ON();
++ mod_timer(&trigoff_timer, jiffies + TRIGOFFINTERVAL);
++}
++
++static void kbd_stop_scanner(unsigned long dummy)
++{
++ RAMSES_SCANNER_TRIG_OFF();
++}
++
++static int kbd_dokeycode(unsigned char scancode, int down)
++{
++ int i,keycode;
++
++ //DPRINTK("calling with (%d,%x,%d)\n", scancode, scancode, down);
++ if (scancode >= MAX_SCANCODES) {
++ printk("%s: scancode too big for table\n", __FUNCTION__);
++ return 0;
++ }
++
++ keycode = ramses_keymap[scancode][curr_map];
++
++
++ if (keycode==KEY_SCAN) {
++ if ((ramses_flags & RAMSES_FLAGS_KEY_SCAN) == 0)
++ return 0;
++
++ DPRINTK("scan btn\n");
++ if (down) {
++ if (ramses_flags & RAMSES_FLAGS_SCANNER_BEAM) {
++ // just turn on laser beam
++ RAMSES_SCANNER_WAKE_ON();
++ } else {
++ kbd_start_scanner();
++ }
++ } else {
++ if (ramses_flags & RAMSES_FLAGS_SCANNER_BEAM) {
++ kbd_start_scanner();
++ } else {
++ kbd_stop_scanner(0);
++ }
++ }
++ return 0;
++ }
++
++
++ if (keycode==KEY_SUSP) {
++ if ((ramses_flags & RAMSES_FLAGS_KEY_SUSPEND) == 0)
++ return 0;
++
++ if (down) {
++ suspend_counter++;
++ if (suspend_counter >= SUSPEND_COUNTER) {
++ suspend_counter = SUSPEND_NOW;
++ }
++ } else {
++ if (suspend_counter == SUSPEND_NOW) {
++ curr_map = MAP_NORMAL;
++ schedule_task(&tq_suspend);
++ }
++ suspend_counter = 0;
++ }
++ return down;
++ }
++
++
++ if (keycode==KEY_OFF) {
++ if (down || ((ramses_flags & RAMSES_FLAGS_KEY_OFF) == 0))
++ return 0;
++ curr_map = MAP_NORMAL;
++ ramses_shut_off();
++ return 0;
++ }
++
++
++ if (!down)
++ return 0;
++
++
++ DPRINTK("curr_map %d scancode %d keycode %d 0x%x typ %d\n", curr_map, scancode, keycode, keycode, KMOD(keycode));
++
++
++ // Cell-Phone keyboard handling
++ if (KMOD(keycode)==KM_CELL) {
++ //DPRINTK("cell phone key %d\n", KVAL(keycode));
++
++ // did we press a different cell-phone key as last time?
++ if (KVAL(keycode)!=cell_key)
++ kbd_cell_timer(1);
++
++ cell_key = KVAL(keycode); // store current cell-phone key
++ cell_sel++; // increase current sub-key
++ if (ramses_cellmap[cell_key][cell_sel]==0) // if at end of sub-key list, back off
++ cell_sel = 0;
++ //DPRINTK("cell_key: %d cell_sel: %d\n", cell_key, cell_sel);
++ // auto-emit via kbd_cell_timer
++ mod_timer(&cell_timer, jiffies + CELLINTERVAL);
++ return 0; // do not revert to keys_normal
++ }
++
++
++ // if we pressed any other key then a cell-phone key, we look if the
++ // current half-pressed cell-phone key should be emitted
++ kbd_cell_timer(1);
++
++
++ switch(keycode) {
++
++ // Keymap handling
++
++ case KEY_NORM:
++ DPRINTK("norm key map\n");
++ curr_map = MAP_NORMAL;
++ return 0;
++
++ case KEY_BLUE:
++ //DPRINTK("blue key map\n");
++ curr_map = MAP_BLUE;
++ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
++ return 0;
++
++ case KEY_ORNG:
++ //DPRINTK("orange key map\n");
++ curr_map = MAP_ORANGE;
++ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
++ return 0;
++
++ case KEY_CAPS:
++ DPRINTK("caps key map\n");
++ curr_map = MAP_CAPS;
++ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
++ return 0;
++
++ case KEY_BRIP:
++ i = ramses_lcd_get_brightness()-6;
++ ramses_lcd_set_brightness(i);
++ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
++ return 0;
++
++ case KEY_BRIM:
++ i = ramses_lcd_get_brightness()+6;
++ ramses_lcd_set_brightness(i);
++ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
++ return 0;
++
++ case KEY_CTRM:
++ i = ramses_lcd_get_contrast()+3;
++ ramses_lcd_set_contrast(i);
++ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
++ return 0;
++
++ case KEY_CTRP:
++ i = ramses_lcd_get_contrast()-3;
++ ramses_lcd_set_contrast(i);
++ mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap
++ return 0;
++ }
++
++ // normal keys
++
++ ramses_key(keycode);
++
++ if (curr_map!=MAP_NORMAL)
++ DPRINTK("back to normal map\n");
++ curr_map = MAP_NORMAL;
++ RAMSES_LED_BLUE_OFF();
++ RAMSES_LED_ORANGE_OFF();
++ return 0;
++}
++
++
++/**
++ * @param rescan 0 if we look for pressed keys, 1 if we look for released keys
++ *
++ * This routine get's called from the ISR (then rescan is always 0) or from
++ * the reenable_timer function (then rescan is 1).
++ */
++static void kbd_scan_keyboard(unsigned long rescan)
++{
++ int i,n;
++ int cols;
++ unsigned char code;
++ __u16 keystate_xor[KEYBD_MATRIX_NUMBER_OUTPUTS];
++
++
++ // Find out if a key (or more) was pressed down. It's possible that
++ // because of spikes we got an interrupt, but when the IRQ service
++ // routine fired there is currently no detectable key. If this is
++ // true, then delay some times and re-try, but not too often.
++
++ cols = 0;
++ for(n=0; n<10; n++) {
++ for (i = 0; i < KEYBD_MATRIX_NUMBER_OUTPUTS; i++) {
++ KEYBD_MATRIX_SET_OUTPUTS( 1 << i );
++ udelay(KEYBD_MATRIX_SETTLING_TIME_US);
++ KEYBD_MATRIX_GET_INPUTS(keystate_cur[i]);
++ if (keystate_cur[i])
++ cols++;
++ }
++ if (cols || rescan)
++ break;
++ udelay(KEYBD_MATRIX_SETTLING_TIME_US*50);
++ }
++
++ // if rescan is true, we are in the process of turning on the IRQ.
++ // Ignore any spurious IRQ. However, if we got an IRQ but could not
++ // detect any key, we note this on the console, clear the keystate
++ // completely and make sure the IRQ gets re-enabled via the timer
++ // shortly.
++
++ if (!cols && !rescan) {
++ printk("%s: spurious kbd int\n", __FUNCTION__);
++ for (i = 0; i < KEYBD_MATRIX_NUMBER_OUTPUTS; i++) {
++ keystate_cur[i] = 0;
++ keystate_prev[i] = 0;
++ }
++ mod_timer(&reenable_timer, jiffies + SCANINTERVAL);
++ return;
++ }
++
++ pm_access(pm_keyb);
++
++ // Okay, all went well. We now keystate_cur[] may contain the rows
++ // where we had keypresses, e.g.
++ // 0 0 0 2 0 0 0 0 0 0 0 0 0 0
++ // We would see this if DEBUG_DUMP_KEYSTATE is on:
++
++#ifdef DEBUG_DUMP_KEYSTATE
++ cols = 0;
++ for (i = 0; i < KEYBD_MATRIX_NUMBER_OUTPUTS; i++) {
++ printk("%d-%d ",keystate_cur[i], keystate_keep[i]);
++ }
++ printk("\n");
++#endif
++
++ cols = 0;
++ for (i = 0; i < KEYBD_MATRIX_NUMBER_OUTPUTS; i++) {
++
++ // detect which key has changes doing an XOR of old state with new state
++ keystate_xor[i] = keystate_prev[i] ^ keystate_cur[i];
++ //printk("%d: prev %d cur %d xor %d keep %d\n", i, keystate_prev[i], keystate_cur[i], keystate_xor[i], keystate_keep[i]);
++
++ // some key changed, find out which one and do the scancode handling
++ if (keystate_xor[i] || keystate_keep[i]) {
++ for (n = 0; n < KEYBD_MATRIX_NUMBER_INPUTS; n++)
++ {
++ if ( (keystate_keep[i] & keystate_cur[i]) ||
++ (keystate_xor[i] & (1 << n)) )
++ {
++ int res;
++ code = n * KEYBD_MATRIX_NUMBER_OUTPUTS + i + 1;
++ res = kbd_dokeycode(code, keystate_cur[i] & (1 << n) ? 1 : 0);
++ kbd_setleds();
++ if (res) {
++ keystate_keep[i] = 1 << n;
++ goto out;
++ }
++ }
++ }
++ }
++out:
++ keystate_prev[i] = keystate_cur[i];
++ }
++
++
++ // fire reenable time if we are in the ISR
++ if (!rescan)
++ mod_timer(&reenable_timer, jiffies + SCANINTERVAL);
++}
++
++
++
++static void kbd_reenable_timer(unsigned long dummy)
++{
++ // re-scan the keyboard (to detect released keys)
++ kbd_scan_keyboard(1);
++
++ // re-enable interrupts from the CPLD
++ KEYBD_MATRIX_SET_OUTPUTS( KEYBD_MATRIX_OUTPUT_MASK );
++}
++
++
++
++
++
++/**
++ * Referenced by request_irq()
++ */
++static void kbd_interrupt(int irq, void *dummy, struct pt_regs *fp)
++{
++ kbd_scan_keyboard(0);
++}
++
++static void ramseskbd_suspend(void *data)
++{
++ pm_suggest_suspend();
++}
++
++
++static int __init ramseskbd_init(void)
++{
++ int irq_gpio_pin;
++
++ // Activate the normal pc-keycodes for the input-layer-keyboard
++ k_setkeycode = input_setkeycode;
++ k_getkeycode = input_getkeycode;
++ k_translate = input_translate;
++ k_unexpected_up = input_unexpected_up;
++#ifdef CONFIG_MAGIC_SYSRQ
++ k_sysrq_key = 0x54;
++ k_sysrq_xlate = input_sysrq_xlate;
++#endif
++
++ // In linux-2.5.x we can do
++ // init_input_dev(&ramses_kbd_dev);
++ // but here we don't have this on linux-2.4, so we fill it with zeros:
++ memset(&ramses_kbd_dev, 0, sizeof(ramses_kbd_dev));
++ ramses_kbd_dev.name = kbd_name;
++
++ // which events we can produce (only keypresses):
++ ramses_kbd_dev.evbit[0] = BIT(EV_KEY);
++
++ // which keypresses we can produce (all):
++ memset(&ramses_kbd_dev.keybit, 0xff, sizeof(ramses_kbd_dev.keybit));
++
++ // We set the 14 output columns to 0. This stops the CPLD to
++ // generate an IRQ before we finished our setup
++ KEYBD_MATRIX_SET_OUTPUTS(0);
++
++ // Turn all LEDs off, meaning that we have the normal keymap active
++ RAMSES_LED_BLUE_OFF();
++ RAMSES_LED_ORANGE_OFF();
++ // TODO: used leds.c?
++
++ // Now we make sure that the GPIO for our IRQ is programmed correctly
++ irq_gpio_pin = IRQ_TO_GPIO_2_80(RAMSES_KEYBOARD_IRQ);
++ GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin);
++ set_GPIO_IRQ_edge(irq_gpio_pin, RAMSES_KEYBOARD_IRQ_EDGE);
++ request_irq(RAMSES_KEYBOARD_IRQ, kbd_interrupt, 0, kbd_name, NULL);
++
++ // Initialize timer to re-enable IRQs. That's our method of keyboard de-prelling
++ init_timer(&reenable_timer);
++ reenable_timer.function = kbd_reenable_timer;
++
++ init_timer(&trigoff_timer);
++ trigoff_timer.function = kbd_stop_scanner;
++
++ // Initialize to escape the blue mode, so we emit the current cell-phone key
++ init_timer(&cell_timer);
++ cell_timer.function = kbd_cell_timer;
++
++ tq_suspend.routine = ramseskbd_suspend;
++
++ // Register with Power-Management
++#ifdef PM_DEBUG
++ pm_keyb = pm_register(PM_SYS_DEV, PM_SYS_KBC+1, NULL, "ramses_keyb");
++#else
++ pm_keyb = pm_register(PM_SYS_DEV, PM_SYS_KBC+1, NULL);
++#endif
++
++ // Register our keyboard
++ input_register_device(&ramses_kbd_dev);
++
++ // We set the 14 output columns to 1. This allows the CPLD to
++ // generate an IRQ when one of the rows goes high
++ KEYBD_MATRIX_SET_OUTPUTS(KEYBD_MATRIX_OUTPUT_MASK);
++
++ return 0;
++}
++
++
++static void __exit ramseskbd_exit(void)
++{
++ // make IRQs impossible, return the IRQ and unregister us
++ KEYBD_MATRIX_SET_OUTPUTS(0);
++ free_irq(RAMSES_KEYBOARD_IRQ, NULL);
++ pm_unregister(pm_keyb);
++ input_unregister_device(&ramses_kbd_dev);
++}
++
++
++module_init(ramseskbd_init);
++module_exit(ramseskbd_exit);
++
++MODULE_AUTHOR("Holger Schurig <h.schurig@mn-logistik.de>");
++MODULE_DESCRIPTION("Ramses keyboard driver");
++MODULE_LICENSE("GPL");
++EXPORT_SYMBOL(ramses_key);
++EXPORT_SYMBOL(ramses_kbd_dev);
+--- /dev/null
++++ linux-2.4.21/drivers/input/ramses_keymap.h
+@@ -0,0 +1,68 @@
++// Normal Map
++static int ramses_keymap[][6] = {
++/* Normal Blue Orange Caps Spare Spare */
++/* 0 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 1 */ {KEY_SUSP, KEY_SUSP, KEY_SUSP, KEY_OFF, KEY_SUSP, KEY_SUSP },
++/* 2 */ {KEY_UP, KEY_UP, KEY_PGUP, KEY_UP, KEY_noop, KEY_noop },
++/* 3 */ {KEY_1, KEY_SPACE, KEY_BRIM, KEY_SPACE, KEY_noop, KEY_noop },
++/* 4 */ {KEY_4, KEY_ghi , KEY_CTRM, KEY_GHI , KEY_noop, KEY_noop },
++/* 5 */ {KEY_7, KEY_pqrs, KEY_cel7, KEY_PQRS, KEY_noop, KEY_noop },
++/* 6 */ {KEY_DOT, KEY_uml, KEY_celP, KEY_UML, KEY_noop, KEY_noop },
++/* 7 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 8 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 9 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 10 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 11 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 12 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 13 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 14 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 15 */ {KEY_ENTER, KEY_ENTER, KEY_ENTER, KEY_ENTER, KEY_ENTER, KEY_ENTER},
++/* 16 */ {KEY_DOWN, KEY_DOWN, KEY_PGDN, KEY_DOWN, KEY_noop, KEY_noop },
++/* 17 */ {KEY_2, KEY_abc , KEY_BRIP, KEY_ABC , KEY_noop, KEY_noop },
++/* 18 */ {KEY_5, KEY_jkl , KEY_CTRP, KEY_JKL, KEY_noop, KEY_noop },
++/* 19 */ {KEY_8, KEY_tuv , KEY_cel8, KEY_TUV, KEY_noop, KEY_noop },
++
++/* Normal Blue Orange Caps Spare Spare */
++/* 20 */ {KEY_0, KEY_TAB, KEY_cel0, KEY_BTAB, KEY_noop, KEY_noop },
++/* 21 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 22 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 23 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 24 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 25 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 26 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 27 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 28 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 29 */ {KEY_ESC, KEY_ESC, KEY_ESC, KEY_ESC, KEY_ESC, KEY_ESC },
++/* 30 */ {KEY_RIGHT, KEY_RIGHT, KEY_END, KEY_C2, KEY_noop, KEY_noop },
++/* 31 */ {KEY_3, KEY_def, KEY_FXIT, KEY_DEF, KEY_noop, KEY_noop },
++/* 32 */ {KEY_6, KEY_mno , KEY_FRST, KEY_MNO, KEY_noop, KEY_noop },
++/* 33 */ {KEY_9, KEY_wxyz, KEY_cel9, KEY_WXYZ, KEY_noop, KEY_noop },
++/* 34 */ {KEY_BACKSPACE,KEY_ATSIGN,KEY_BAR, KEY_noop, KEY_noop, KEY_noop },
++/* 35 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 36 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 37 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 38 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 39 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++
++/* Normal Blue Orange Caps Spare Spare */
++/* 40 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 41 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 42 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 43 */ {KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN },
++/* 44 */ {KEY_LEFT, KEY_LEFT, KEY_HOME, KEY_C1, KEY_noop, KEY_noop },
++/* 45 */ {KEY_OFF, KEY_OFF, KEY_OFF, KEY_OFF, KEY_OFF, KEY_OFF },
++/* 46 */ {KEY_F1, KEY_F4, KEY_F7, KEY_F10, KEY_noop, KEY_noop },
++/* 47 */ {KEY_F2, KEY_F5, KEY_F8, KEY_F11, KEY_noop, KEY_noop },
++/* 48 */ {KEY_F3, KEY_F6, KEY_F9, KEY_F12, KEY_noop, KEY_noop },
++/* 49 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 50 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 51 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 52 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 53 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 54 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 55 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 56 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop },
++/* 57 */ {KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN },
++/* 58 */ {KEY_BLUE, KEY_NORM, KEY_CAPS, KEY_NORM, KEY_NORM, KEY_NORM },
++/* 59 */ {KEY_ORNG, KEY_CAPS, KEY_NORM, KEY_NORM, KEY_NORM, KEY_NORM },
++};
+--- /dev/null
++++ linux-2.4.21/drivers/input/ramses_scancodes.h
+@@ -0,0 +1,134 @@
++#ifndef _RAMSES_SCANCODES_H
++#define _RAMSES_SCANCODES_H
++
++#define KMOD(a) (a & 0xff00)
++#undef KVAL
++#define KVAL(a) (a & 0x00ff)
++
++// which modifiers to send before/after
++#define KM_SPECIAL 0x300
++#define KM_CELL 0x400
++#define KM_SHIFT 0x500
++#define KM_ALT 0x600
++#define KM_CTRL 0x700
++#define KM_ALTGR 0x800
++#define KM_ALTCTRL 0x900
++
++// or special keys
++#define KEY_noop KM_SPECIAL + 0
++#define KEY_OFF KM_SPECIAL + 1
++#define KEY_SUSP KM_SPECIAL + 2
++#define KEY_SCAN KM_SPECIAL + 3
++#define KEY_CTRM KM_SPECIAL + 4
++#define KEY_CTRP KM_SPECIAL + 5
++#define KEY_BRIM KM_SPECIAL + 6
++#define KEY_BRIP KM_SPECIAL + 7
++
++#define KEY_NORM KM_SPECIAL + 10
++#define KEY_BLUE KM_SPECIAL + 11
++#define KEY_ORNG KM_SPECIAL + 12
++#define KEY_CAPS KM_SPECIAL + 13
++
++
++// our cell-phone like keys
++#define KEY_abc KM_CELL + 0
++#define KEY_def KM_CELL + 1
++#define KEY_ghi KM_CELL + 2
++#define KEY_jkl KM_CELL + 3
++#define KEY_mno KM_CELL + 4
++#define KEY_pqrs KM_CELL + 5
++#define KEY_tuv KM_CELL + 6
++#define KEY_wxyz KM_CELL + 7
++#define KEY_uml KM_CELL + 8
++#define KEY_ABC KM_CELL + 9
++#define KEY_DEF KM_CELL + 10
++#define KEY_GHI KM_CELL + 11
++#define KEY_JKL KM_CELL + 12
++#define KEY_MNO KM_CELL + 13
++#define KEY_PQRS KM_CELL + 14
++#define KEY_TUV KM_CELL + 15
++#define KEY_WXYZ KM_CELL + 16
++#define KEY_UML KM_CELL + 17
++#define KEY_cel7 KM_CELL + 18
++#define KEY_cel8 KM_CELL + 19
++#define KEY_cel9 KM_CELL + 20
++#define KEY_celP KM_CELL + 21
++#define KEY_cel0 KM_CELL + 22
++
++// Shift-Keys
++#define KEY_sA KM_SHIFT + KEY_A
++#define KEY_sB KM_SHIFT + KEY_B
++#define KEY_sC KM_SHIFT + KEY_C
++#define KEY_sD KM_SHIFT + KEY_D
++#define KEY_sE KM_SHIFT + KEY_E
++#define KEY_sF KM_SHIFT + KEY_F
++#define KEY_sG KM_SHIFT + KEY_G
++#define KEY_sH KM_SHIFT + KEY_H
++#define KEY_sI KM_SHIFT + KEY_I
++#define KEY_sJ KM_SHIFT + KEY_J
++#define KEY_sK KM_SHIFT + KEY_K
++#define KEY_sL KM_SHIFT + KEY_L
++#define KEY_sM KM_SHIFT + KEY_M
++#define KEY_sN KM_SHIFT + KEY_N
++#define KEY_sO KM_SHIFT + KEY_O
++#define KEY_sP KM_SHIFT + KEY_P
++#define KEY_sQ KM_SHIFT + KEY_Q
++#define KEY_sR KM_SHIFT + KEY_R
++#define KEY_sS KM_SHIFT + KEY_S
++#define KEY_sT KM_SHIFT + KEY_T
++#define KEY_sU KM_SHIFT + KEY_U
++#define KEY_sV KM_SHIFT + KEY_V
++#define KEY_sW KM_SHIFT + KEY_W
++#define KEY_sX KM_SHIFT + KEY_X
++#define KEY_sY KM_SHIFT + KEY_Y
++#define KEY_sZ KM_SHIFT + KEY_Z
++
++// Umlaute
++#define KEY_sAE KM_SHIFT + 40
++#define KEY_sOE KM_SHIFT + 39
++#define KEY_sUE KM_SHIFT + 26
++#define KEY_AE 40
++#define KEY_OE 39
++#define KEY_UE 26
++#define KEY_SZ 12
++
++// AS400-Keys
++#define KEY_FRST KM_ALT + KEY_R
++#define KEY_FXIT KM_ALT + KEY_X
++
++// Console-Switch
++#define KEY_C1 KM_ALTCTRL + KEY_F1
++#define KEY_C2 KM_ALTCTRL + KEY_F2
++
++// additional keys from the german keyboard
++#undef KEY_MINUS
++#undef KEY_EQUAL
++#undef KEY_Y
++#undef KEY_Z
++#define KEY_Y 44
++#define KEY_Z 21
++#define KEY_STAR 55
++#define KEY_COLON KM_SHIFT + 52
++#define KEY_UNDERL KM_SHIFT + 53
++#define KEY_ATSIGN KM_ALTGR + 16
++#define KEY_BAR KM_ALTGR + 86
++#define KEY_EQUAL KM_SHIFT + 11
++#define KEY_SEMI KM_SHIFT + 51
++#define KEY_BSLASH KM_ALTGR + 12
++#define KEY_FSLASH KM_SHIFT + KEY_7
++#define KEY_MINUS 53
++#define KEY_PLUS 27
++#define KEY_GAENSE KM_SHIFT + 3
++#define KEY_PARA KM_SHIFT + 4
++#define KEY_HASH 43
++#define KEY_PGUP KEY_PAGEUP
++#define KEY_PGDN KEY_PAGEDOWN
++#define KEY_BTAB KM_SHIFT + KEY_TAB
++
++#define MAP_NORMAL 0
++#define MAP_BLUE 1
++#define MAP_ORANGE 2
++#define MAP_CAPS 3
++#define MAX_SCANCODES 100
++
++#endif
+--- /dev/null
++++ linux-2.4.21/drivers/input/wedge.c
+@@ -0,0 +1,241 @@
++/*
++ * Virtual keyboard wedge using input layer
++ *
++ * (C) 2002,2003 by M&N Logistik-Lösungen Online GmbH
++ * written by H.Schurig
++ *
++ * Creates a misc char device /dev/misc/wedge. Any output to this
++ * device will be translated (via a german keyboard map) into scancodes
++ * and re-submitted into the keyboard channel. Any console, X-Windows
++ * or Qt/Embedded application will be able to receive this info.
++ */
++
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/miscdevice.h>
++#include <linux/input.h>
++
++#include <linux/types.h>
++#include <linux/keyboard.h>
++#include <linux/kd.h>
++
++#include <asm/uaccess.h>
++
++
++// Debug
++//#define DEBUG 1
++#ifdef DEBUG
++# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
++# define PRINTK(fmt, args...) printk(fmt, ## args)
++#else
++# define DPRINTK(fmt, args...)
++# define PRINTK(fmt, args...)
++#endif
++
++
++// Defines
++#define KBD_STUFF_MAX_BYTES 512
++
++// Für den IOCTL
++#define WEDGE_RAWKEY_DOWN _IOW('w', 0x72, unsigned long)
++#define WEDGE_RAWKEY_UP _IOW('w', 0x73, unsigned long)
++#define WEDGE_TS_ABS_X _IOW('w', 0x74, unsigned long)
++#define WEDGE_TS_ABS_Y _IOW('w', 0x75, unsigned long)
++#define WEDGE_TS_ABS_PRESSURE _IOW('w', 0x76, unsigned long)
++
++// Externs
++#define MAX_NR_KEYMAPS 256
++extern void ramses_key(int keycode);
++extern unsigned short *key_maps[MAX_NR_KEYMAPS];
++extern struct input_dev ramses_kbd_dev;
++extern void ucb1x00_ts_evt_add(void *, u16 pressure, u16 x, u16 y);
++
++// for special keys
++struct wedge_lookup_t {
++ u_short c;
++ u_short keysym;
++};
++
++struct wedge_lookup_t wedge_lookup[] = {
++ { 0x0a, 0x001c, },
++ { 0x2f, 0x0508, },
++};
++
++
++
++
++static void *outbuf;
++
++static int wedge_open(struct inode *inode, struct file *filp)
++{
++ int ret;
++
++ ret = -ENXIO;
++ outbuf = kmalloc(KBD_STUFF_MAX_BYTES, GFP_KERNEL);
++ if (!outbuf)
++ goto out;
++
++ ret = 0;
++
++out:
++ if (ret) {
++ kfree(outbuf);
++ }
++ return ret;
++}
++
++
++static int wedge_close(struct inode *inode, struct file *filp)
++{
++ kfree(outbuf);
++ return 0;
++}
++
++
++static int wedge_search_map(u_short map[], int c)
++{
++ int i;
++
++ for (i=0; i<NR_KEYS; i++) {
++ if (map[i] == (c | 0xf000))
++ return i;
++ if (map[i] == (c | 0xfb00))
++ return i;
++ }
++
++ return 0;
++}
++
++
++static void wedge_handle_char(int c)
++{
++ int i;
++ unsigned int maps;
++ u_short *map;
++
++ DPRINTK("wedge_handle_char(0x%0x)\n", c);
++
++ for (i=0; i < sizeof(wedge_lookup)/sizeof(wedge_lookup[0]); i++) {
++ if (wedge_lookup[i].c == c) {
++ ramses_key(wedge_lookup[i].keysym);
++ return;
++ }
++ }
++
++
++ i = 0;
++ for (maps=0; maps<MAX_NR_KEYMAPS; maps++) {
++ map = key_maps[maps];
++ if (!map)
++ continue;
++ if ((i = wedge_search_map(map, c))) {
++ switch(maps) {
++ case 0:
++ break;
++ case 1:
++ i |= 0x500; // KT_SHIFT from ramses_scancodes.h
++ break;
++ case 2:
++ i |= 0x800; // KT_ALTGR from ramses_scancodes.h
++ break;
++ case 4:
++ i |= 0x700; // KT_CTRL from ramses_scancodes.h
++ break;
++ default:
++ DPRINTK("unknown map for char %d %d\n", c, maps);
++ }
++ DPRINTK("ramses_key(0x%x)\n", i);
++ ramses_key(i);
++ return;
++ }
++ }
++
++ DPRINTK("entry for char %02x missing\n", c);
++}
++
++
++
++static ssize_t wedge_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
++{
++ const char *p = buf;
++ char c;
++
++ //DPRINTK("count=%d\n", count);
++ while (count) {
++ if (copy_from_user(&c, p, sizeof(c)))
++ return -EFAULT;
++
++ p++;
++ count--;
++
++ wedge_handle_char( (int)c & 0xff);
++
++ }
++ return p - buf;
++}
++
++
++int wedge_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++ static u16 x;
++ static u16 y;
++ static u16 p;
++
++ switch (cmd) {
++ case WEDGE_RAWKEY_DOWN:
++ DPRINTK("send down raw key\n");
++ input_report_key(&ramses_kbd_dev, arg, 1);
++ return 0;
++ case WEDGE_RAWKEY_UP:
++ DPRINTK("send up raw key\n");
++ input_report_key(&ramses_kbd_dev, arg, 0);
++ return 0;
++ case WEDGE_TS_ABS_X:
++ x = arg;
++ return 0;
++ case WEDGE_TS_ABS_Y:
++ y = arg;
++ return 0;
++ case WEDGE_TS_ABS_PRESSURE:
++ p = arg;
++ ucb1x00_ts_evt_add(NULL, arg, y, x);
++ return 0;
++ }
++ return -EINVAL;
++}
++
++
++static struct file_operations wedge_fops = {
++ owner: THIS_MODULE,
++ write: wedge_write,
++ open: wedge_open,
++ release: wedge_close,
++ ioctl: wedge_ioctl,
++};
++
++
++static struct miscdevice wedge_miscdev = {
++ minor: MISC_DYNAMIC_MINOR,
++ name: "wedge",
++ fops: &wedge_fops,
++};
++
++static int __init wedge_init(void)
++{
++ int ret;
++ ret = misc_register(&wedge_miscdev);
++ DPRINTK("major,minor is 10,%d\n", wedge_miscdev.minor);
++ return ret;
++}
++
++static void __exit wedge_exit(void)
++{
++ misc_deregister(&wedge_miscdev);
++}
++
++module_init(wedge_init);
++module_exit(wedge_exit);
++
++MODULE_DESCRIPTION("virtual keyboard wedge");
++MODULE_LICENSE("GPL");
+--- linux-2.4.21/drivers/misc/Makefile~wedge
++++ linux-2.4.21/drivers/misc/Makefile
+@@ -12,7 +12,7 @@
+ O_TARGET := misc.o
+
+ export-objs := mcp-core.o mcp-sa1100.o mcp-pxa.o \
+- ucb1x00-core.o
++ ucb1x00-core.o ucb1x00-ts.o
+
+ obj-$(CONFIG_MCP_SA1100) += mcp-core.o mcp-sa1100.o
+ obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
+--- linux-2.4.21/drivers/misc/mcp-pxa.c~ucb1x00
++++ linux-2.4.21/drivers/misc/mcp-pxa.c
+@@ -31,6 +31,11 @@
+ return (struct mcp *)codec;
+ }
+
++void mcp_put(void)
++{
++ pxa_ac97_put();
++}
++
+ void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val)
+ {
+ struct ac97_codec *codec = (struct ac97_codec *)mcp;
+@@ -55,3 +60,7 @@
+ void mcp_disable(struct mcp *mcp)
+ {
+ }
++
++MODULE_AUTHOR("Jeff Sutherland <jeffs@accelent.com>");
++MODULE_DESCRIPTION("PXA mcp low level support");
++MODULE_LICENSE("GPL");
+--- linux-2.4.21/drivers/misc/mcp.h~ucb1x00
++++ linux-2.4.21/drivers/misc/mcp.h
+@@ -43,6 +43,7 @@
+
+ /* noddy implementation alert! */
+ struct mcp *mcp_get(void);
++void mcp_put(void);
+ int mcp_register(struct mcp *);
+
+ #define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
+--- linux-2.4.21/drivers/misc/ucb1x00-core.c~pm
++++ linux-2.4.21/drivers/misc/ucb1x00-core.c
+@@ -25,6 +25,7 @@
+ #include <linux/pm.h>
+ #include <linux/tqueue.h>
+ #include <linux/config.h>
++#include <linux/delay.h>
+
+ #include <asm/irq.h>
+ #include <asm/mach-types.h>
+@@ -181,8 +182,9 @@
+ if (val & UCB_ADC_DAT_VAL)
+ break;
+ /* yield to other processes */
+- set_current_state(TASK_INTERRUPTIBLE);
+- schedule_timeout(1);
++ //HS set_current_state(TASK_INTERRUPTIBLE);
++ //HS schedule_timeout(1);
++ udelay(200);
+ }
+
+ return UCB_ADC_DAT(val);
+@@ -209,7 +211,8 @@
+ struct ucb1x00 *ucb = (struct ucb1x00 *)dev->data;
+ unsigned int isr;
+
+- if (rqst == PM_RESUME) {
++ switch (rqst) {
++ case PM_RESUME:
+ ucb1x00_enable(ucb);
+ isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS);
+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
+@@ -521,7 +524,9 @@
+ */
+ static int __init ucb1x00_configure(struct ucb1x00 *ucb)
+ {
++#ifndef CONFIG_ARCH_RAMSES
+ unsigned int irq_gpio_pin = 0;
++#endif
+ int irq, default_irq = NO_IRQ;
+
+ #ifdef CONFIG_ARCH_SA1100
+@@ -611,11 +616,13 @@
+ /*
+ * Eventually, this will disappear.
+ */
++#ifndef CONFIG_ARCH_RAMSES
+ 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
+ #endif
+ irq = ucb1x00_detect_irq(ucb);
+ if (irq != NO_IRQ) {
+--- linux-2.4.21/drivers/misc/ucb1x00-ts.c~ramses-ucb1x00-dejitter
++++ linux-2.4.21/drivers/misc/ucb1x00-ts.c
+@@ -29,6 +29,7 @@
+
+ #include <asm/dma.h>
+ #include <asm/semaphore.h>
++#include <asm/hardware.h>
+
+ #include "ucb1x00.h"
+
+@@ -97,7 +98,7 @@
+ };
+
+ static struct ucb1x00_ts ucbts;
+-static int adcsync = UCB_NOSYNC;
++static int adcsync = UCB_SYNC;
+
+ static int ucb1x00_ts_startup(struct ucb1x00_ts *ts);
+ static void ucb1x00_ts_shutdown(struct ucb1x00_ts *ts);
+@@ -116,8 +117,14 @@
+ next_head = (ts->evt_head + 1) & (NR_EVENTS - 1);
+ if (next_head != ts->evt_tail) {
+ ts->events[ts->evt_head].pressure = pressure;
++#if 0
+ ts->events[ts->evt_head].x = x;
+ ts->events[ts->evt_head].y = y;
++#else
++ // rotate by -90
++ ts->events[ts->evt_head].x = y;
++ ts->events[ts->evt_head].y = x;
++#endif
+ do_gettimeofday(&ts->events[ts->evt_head].stamp);
+ ts->evt_head = next_head;
+
+@@ -256,11 +263,11 @@
+
+ #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)
++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_report_abs(&ucbts.idev, ABS_X, y);
++ input_report_abs(&ucbts.idev, ABS_Y, x);
++ input_report_abs(&ucbts.idev, ABS_PRESSURE, pressure);
+ }
+
+ static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
+@@ -335,7 +342,7 @@
+ 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);
++ return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSMY, ts->adcsync);
+ }
+
+ /*
+@@ -346,19 +353,15 @@
+ */
+ 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);
++ unsigned int res;
+ 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);
++ udelay(600);
+
+- return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
++ res = ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSMY, ts->adcsync);
++ return res;
+ }
+
+ /*
+@@ -369,19 +372,15 @@
+ */
+ static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts)
+ {
++ unsigned int res;
+ 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_TSPY_GND | UCB_TS_CR_TSMY_POW |
+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
+
+- udelay(55);
++ udelay(300);
+
+- return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
++ res = ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
++ return res;
+ }
+
+ /*
+@@ -430,8 +429,9 @@
+ * 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;
++//HS
++ tsk->policy = SCHED_FIFO;
++ tsk->rt_priority = 1;
+
+ /* only want to receive SIGKILL */
+ spin_lock_irq(&tsk->sigmask_lock);
+@@ -451,8 +451,8 @@
+ ucb1x00_adc_enable(ts->ucb);
+
+ x = ucb1x00_ts_read_xpos(ts);
+- y = ucb1x00_ts_read_ypos(ts);
+ p = ucb1x00_ts_read_pressure(ts);
++ y = ucb1x00_ts_read_ypos(ts);
+
+ /*
+ * Switch back to interrupt mode.
+@@ -461,7 +461,7 @@
+ ucb1x00_adc_disable(ts->ucb);
+
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+- schedule_timeout(HZ / 100);
++ schedule_timeout(HZ / 200);
+ if (signal_pending(tsk))
+ break;
+
+@@ -504,7 +504,7 @@
+ }
+
+ set_task_state(tsk, TASK_INTERRUPTIBLE);
+- schedule_timeout(HZ / 100);
++ schedule_timeout(HZ / 200);
+ }
+
+ if (signal_pending(tsk))
+@@ -655,8 +655,8 @@
+ char *p;
+
+ while ((p = strsep(&str, ",")) != NULL) {
+- if (strcmp(p, "sync") == 0)
+- adcsync = UCB_SYNC;
++ if (strcmp(p, "nosync") == 0)
++ adcsync = UCB_NOSYNC;
+ }
+
+ return 1;
+@@ -674,6 +674,7 @@
+ module_init(ucb1x00_ts_init);
+ module_exit(ucb1x00_ts_exit);
+
++EXPORT_SYMBOL(ucb1x00_ts_evt_add);
+ MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+ MODULE_DESCRIPTION("UCB1x00 touchscreen driver");
+ MODULE_LICENSE("GPL");
+--- linux-2.4.21/drivers/mtd/maps/Config.in~ramses-mtd
++++ linux-2.4.21/drivers/mtd/maps/Config.in
+@@ -76,6 +76,7 @@
+
+ if [ "$CONFIG_ARM" = "y" ]; then
+ dep_tristate ' CFI Flash device mapped on Lubbock board' CONFIG_MTD_LUBBOCK $CONFIG_MTD_CFI $CONFIG_ARCH_LUBBOCK $CONFIG_MTD_PARTITIONS
++ dep_tristate ' CFI Flash device mapped on Ramses board' CONFIG_MTD_RAMSES $CONFIG_MTD_CFI $CONFIG_ARCH_RAMSES $CONFIG_MTD_PARTITIONS
+ dep_tristate ' CFI Flash device mapped on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI
+ dep_tristate ' CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI
+ dep_tristate ' Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712
+--- linux-2.4.21/drivers/mtd/maps/Makefile~ramses-mtd
++++ linux-2.4.21/drivers/mtd/maps/Makefile
+@@ -16,6 +16,7 @@
+ obj-$(CONFIG_MTD_EPXA) += epxa-flash.o
+ obj-$(CONFIG_MTD_IQ80310) += iq80310.o
+ obj-$(CONFIG_MTD_LUBBOCK) += lubbock.o
++obj-$(CONFIG_MTD_RAMSES) += ramses.o
+ obj-$(CONFIG_MTD_PXA_CERF) += pxa_cerf.o
+ obj-$(CONFIG_MTD_TRIZEPS2) += trizeps2.o
+ obj-$(CONFIG_MTD_L440GX) += l440gx.o
+--- /dev/null
++++ linux-2.4.21/drivers/mtd/maps/ramses.c
+@@ -0,0 +1,167 @@
++/*
++ * Map driver for the Ramses developer platform.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <asm/io.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++
++#define WINDOW_ADDR 0
++#define WINDOW_SIZE 32*1024*1024
++
++static __u8 ramses_read8(struct map_info *map, unsigned long ofs)
++{
++ return *(__u8 *)(map->map_priv_1 + ofs);
++}
++
++static __u16 ramses_read16(struct map_info *map, unsigned long ofs)
++{
++ return *(__u16 *)(map->map_priv_1 + ofs);
++}
++
++static __u32 ramses_read32(struct map_info *map, unsigned long ofs)
++{
++ return *(__u32 *)(map->map_priv_1 + ofs);
++}
++
++static void ramses_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++ memcpy(to, (void *)(map->map_priv_1 + from), len);
++}
++
++static void ramses_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ *(__u8 *)(map->map_priv_1 + adr) = d;
++}
++
++static void ramses_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ *(__u16 *)(map->map_priv_1 + adr) = d;
++}
++
++static void ramses_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ *(__u32 *)(map->map_priv_1 + adr) = d;
++}
++
++static void ramses_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
++{
++ memcpy((void *)(map->map_priv_1 + to), from, len);
++}
++
++static struct map_info ramses_map = {
++ name: "Flash",
++ size: WINDOW_SIZE,
++ read8: ramses_read8,
++ read16: ramses_read16,
++ read32: ramses_read32,
++ copy_from: ramses_copy_from,
++ write8: ramses_write8,
++ write16: ramses_write16,
++ write32: ramses_write32,
++ copy_to: ramses_copy_to
++};
++
++static struct mtd_partition ramses_partitions[] = {
++ {
++ name: "Bootloader",
++ size: 0x00040000,
++ offset: 0,
++ },{
++ name: "Kernel",
++ size: 0x00100000,
++ offset: 0x00040000,
++ },{
++ name: "Filesystem",
++ size: MTDPART_SIZ_FULL,
++ offset: 0x00140000
++ }
++};
++
++#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
++
++static struct mtd_info *mymtd;
++static struct mtd_partition *parsed_parts;
++
++extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
++
++static int __init init_ramses(void)
++{
++ struct mtd_partition *parts;
++ int nb_parts = 0;
++ int parsed_nr_parts = 0;
++ char *part_type = "static";
++
++ ramses_map.buswidth = (BOOT_DEF & 1) ? 2 : 4;
++ printk( "Probing flash at physical address 0x%08x (%d-bit buswidth)\n",
++ WINDOW_ADDR, ramses_map.buswidth * 8 );
++#ifdef CONFIG_ARCH_RAMSES
++ FLASH_WRITE_PROTECT_DISABLE();
++#endif
++ ramses_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0);
++ if (!ramses_map.map_priv_1) {
++ printk("Failed to ioremap\n");
++ return -EIO;
++ }
++ mymtd = do_map_probe("cfi_probe", &ramses_map);
++ if (!mymtd) {
++ iounmap((void *)ramses_map.map_priv_1);
++ return -ENXIO;
++ }
++ mymtd->module = THIS_MODULE;
++
++#ifdef CONFIG_MTD_REDBOOT_PARTS
++ if (parsed_nr_parts == 0) {
++ int ret = parse_redboot_partitions(mymtd, &parsed_parts);
++
++ if (ret > 0) {
++ part_type = "RedBoot";
++ parsed_nr_parts = ret;
++ }
++ }
++#endif
++
++ if (parsed_nr_parts > 0) {
++ parts = parsed_parts;
++ nb_parts = parsed_nr_parts;
++ } else {
++ parts = ramses_partitions;
++ nb_parts = NB_OF(ramses_partitions);
++ }
++ if (nb_parts) {
++ printk(KERN_NOTICE "Using %s partition definition\n", part_type);
++ add_mtd_partitions(mymtd, parts, nb_parts);
++ } else {
++ add_mtd_device(mymtd);
++ }
++ return 0;
++}
++
++static void __exit cleanup_ramses(void)
++{
++ if (mymtd) {
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
++ if (parsed_parts)
++ kfree(parsed_parts);
++ }
++ if (ramses_map.map_priv_1)
++ iounmap((void *)ramses_map.map_priv_1);
++#ifdef CONFIG_ARCH_RAMSES
++ FLASH_WRITE_PROTECT_ENABLE();
++#endif
++ return;
++}
++
++module_init(init_ramses);
++module_exit(cleanup_ramses);
++
+--- linux-2.4.21/drivers/net/irda/pxa_ir.c~pxa-irda
++++ linux-2.4.21/drivers/net/irda/pxa_ir.c
+@@ -38,6 +38,7 @@
+ #include <net/irda/wrapper.h>
+ #include <net/irda/irda_device.h>
+
++#include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/dma.h>
+ #include <asm/hardware.h>
+@@ -786,6 +787,7 @@
+ * Suspend the IrDA interface.
+ */
+
++/*
+ static int pxa250_irda_shutdown(struct pxa250_irda *si)
+ {
+
+@@ -793,6 +795,7 @@
+ return 0;
+
+ }
++*/
+
+
+ static int pxa250_irda_suspend(struct net_device *dev, int state)
+@@ -1141,11 +1144,11 @@
+ /* 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);
++ si->rxbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA ,HPSIR_MAX_RXLEN , &si->rxbuf_dma, 0);
+ 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);
++ si->txbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA, HPSIR_MAX_TXLEN, &si->txbuf_dma, 0);
+ if (! si->txbuf_dma_virt )
+ goto err_txbuf_dma;
+
+--- linux-2.4.21/drivers/net/smc91x.c~pxa-smc91x
++++ linux-2.4.21/drivers/net/smc91x.c
+@@ -46,10 +46,13 @@
+ . 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.
++ . 20/08/03 Holger Schurig add ethtool support
+ ----------------------------------------------------------------------------*/
+
++#define DRV_NAME "smc91x"
++
+ static const char version[] =
+- "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre <nico@cam.org>\n";
++ DRV_NAME ": v1.1 Aug 20 2003 by Nicolas Pitre <nico@cam.org>\n";
+
+ /* Debugging level */
+ #ifndef SMC_DEBUG
+@@ -67,6 +70,7 @@
+ #include <linux/timer.h>
+ #include <linux/errno.h>
+ #include <linux/ioport.h>
++#include <linux/ethtool.h>
+
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+@@ -78,6 +82,7 @@
+ #include <asm/io.h>
+ #include <asm/hardware.h>
+ #include <asm/irq.h>
++#include <asm/uaccess.h>
+
+ #include "smc91x.h"
+
+@@ -105,7 +110,7 @@
+ static int irq = SMC_IRQ;
+
+ #ifndef SMC_NOWAIT
+-# define SMC_NOWAIT 0
++# define SMC_NOWAIT 1
+ #endif
+ static int nowait = SMC_NOWAIT;
+
+@@ -116,6 +121,11 @@
+ MODULE_PARM_DESC(irq, "IRQ number");
+ MODULE_PARM_DESC(nowait, "set to 1 for no wait state");
+
++static int
++smc_read_phy_register(unsigned long ioaddr, int phyaddr, int phyreg);
++static void
++smc_write_phy_register( unsigned long ioaddr, int phyaddr,
++ int phyreg, int phydata );
+
+ /*------------------------------------------------------------------------
+ .
+@@ -143,7 +153,12 @@
+ . 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
++#define THROTTLE_TX_PKTS 1
++
++/*
++ . This defines if we want to compile ethtool support into the driver
++*/
++#define WITH_ETHTOOL 1
+
+
+ /* store this information for the driver.. */
+@@ -310,14 +325,14 @@
+ if (nowait)
+ SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_NO_WAIT );
+
+-#ifdef POWER_DOWN
++#if 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);
++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, status);
+ #endif
+
+ /* this should pause enough for the chip to be happy */
+@@ -390,10 +405,10 @@
+ SMC_SET_RCR( RCR_CLEAR );
+ SMC_SET_TCR( TCR_CLEAR );
+
+-#ifdef POWER_DOWN
++#if 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);
++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, status);
+
+ /* finally, shut the chip down */
+ SMC_SELECT_BANK( 1 );
+@@ -1628,14 +1643,18 @@
+ // 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->rpc_cur_mode = (RPC_ANEG | (RPC_LED_10 << RPC_LSXA_SHFT) | (RPC_LED_TX_RX << RPC_LSXB_SHFT) | RPC_DPLX);
++
++ // 10 MBit/S, auto-negotiation only for 10 MB/s
++ lp->ctl_autoneg = 1;
++ lp->ctl_rfduplx = 1;
+ lp->ctl_rspeed = 10;
+ #else
++ lp->rpc_cur_mode = RPC_DEFAULT;
++
+ lp->ctl_autoneg = 1;
+ lp->ctl_rfduplx = 1;
+ lp->ctl_rspeed = 100;
+@@ -1680,6 +1699,127 @@
+ return 0;
+ }
+
++/*----------------------------------------------------
++ . smc_ioctl
++ .
++ . This ioctl is currently only used by ethtool(8) to
++ . access the serial EEPROM
++ -----------------------------------------------------*/
++
++#if WITH_ETHTOOL
++
++#define SMC91x_EEPROM_SIZE (0x40*2)
++
++u16 smc_eeprom_read(long ioaddr, u16 location)
++{
++ u16 val;
++ u16 oldBank;
++ u16 oldPtr;
++
++ cli();
++ // Save chip settings
++ oldBank = SMC_CURRENT_BANK();
++ SMC_SELECT_BANK( 2 );
++ oldPtr = SMC_GET_PTR();
++
++ // Set location in EEPROM to be read
++ SMC_SET_PTR(location);
++
++ // Set EEPROM_SELECT and RELOAD bits in control register
++ SMC_SELECT_BANK( 1 );
++ val = SMC_GET_CTL();
++ SMC_SET_CTL(val | CTL_EEPROM_SELECT | CTL_RELOAD);
++
++ // Wait until RELEAD is finished
++ while (SMC_GET_CTL() & CTL_RELOAD) ;
++
++ // Get EEPROM data
++ val = SMC_inw(ioaddr, GP_REG);
++
++ // Restore chip settings
++ SMC_SELECT_BANK( 2 );
++ SMC_SET_PTR(oldPtr);
++ SMC_SELECT_BANK( oldBank );
++ sti();
++
++ return val;
++}
++
++static int smc_get_eeprom(struct net_device *dev, u8 *buf)
++{
++ int i;
++ u16 *ebuf = (u16 *)buf;
++
++ for (i = 0; i < SMC91x_EEPROM_SIZE/2; i++) {
++ ebuf[i] = smc_eeprom_read(dev->base_addr, i);
++ }
++ return 0;
++}
++
++static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++ u32 etcmd;
++ int ret = -EINVAL;
++
++ if (cmd != SIOCETHTOOL)
++ return -EOPNOTSUPP;
++
++ if (get_user(etcmd, (u32 *)rq->ifr_data))
++ return -EFAULT;
++
++ switch (etcmd) {
++
++ /* Get driver info */
++ case ETHTOOL_GDRVINFO: {
++ struct ethtool_drvinfo edrv;
++
++ memset(&edrv, 0, sizeof(edrv));
++ edrv.cmd = etcmd;
++ strcpy(edrv.driver, DRV_NAME);
++ sprintf(edrv.bus_info, "ISA:%8.8lx:%d", dev->base_addr, dev->irq);
++ edrv.eedump_len = SMC91x_EEPROM_SIZE;
++ ret = copy_to_user(rq->ifr_data, &edrv, sizeof(edrv)) ? -EFAULT : 0;
++ break;
++ }
++
++ /* Get EEPROM data */
++ case ETHTOOL_GEEPROM: {
++ struct ethtool_eeprom eeprom;
++ u8 eebuf[SMC91x_EEPROM_SIZE];
++ int r;
++
++ if (copy_from_user(&eeprom, rq->ifr_data, sizeof(eeprom)))
++ return -EFAULT;
++
++ if (eeprom.offset > eeprom.offset+eeprom.len)
++ return -EINVAL;
++
++ if ((eeprom.offset+eeprom.len) > SMC91x_EEPROM_SIZE) {
++ eeprom.len = SMC91x_EEPROM_SIZE-eeprom.offset;
++ }
++ eeprom.magic = 0;
++ if (copy_to_user(rq->ifr_data, &eeprom, sizeof(eeprom)))
++ return -EFAULT;
++
++ rq->ifr_data += offsetof(struct ethtool_eeprom, data);
++
++ r = smc_get_eeprom(dev, eebuf);
++
++ if (r)
++ return r;
++ if (copy_to_user(rq->ifr_data, eebuf+eeprom.offset, eeprom.len))
++ return -EFAULT;
++ return 0;
++
++ }
++ }
++
++ return ret;
++}
++
++#endif
++
++
+ /*------------------------------------------------------------
+ . Get the current statistics.
+ . This may be called with the card open or closed.
+@@ -1925,6 +2065,9 @@
+ dev->watchdog_timeo = HZ/10;
+ dev->get_stats = smc_query_statistics;
+ dev->set_multicast_list = smc_set_multicast_list;
++#if WITH_ETHTOOL
++ dev->do_ioctl = smc_ioctl;
++#endif
+
+ return 0;
+
+@@ -1961,12 +2104,17 @@
+ smc_shutdown(global_dev);
+ break;
+ case PM_RESUME:
++ udelay(5000);
+ 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);
++ if (global_dev->flags & IFF_UP) {
++ if (lp->version >= 0x70)
++ smc_phy_configure(global_dev);
++ } else {
++ smc_shutdown(global_dev);
++ }
+ break;
+ }
+ return 0;
+@@ -2054,6 +2202,15 @@
+ int ioaddr = RAMSES_ETH_BASE + 0x300;
+ global_dev->irq = SMC_IRQ;
+ ret = smc_probe(global_dev, ioaddr);
++#ifdef POWER_DOWN
++ smc_shutdown(global_dev);
++#endif
++ }
++#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) {
+@@ -2083,7 +2240,11 @@
+ #ifdef CONFIG_PM
+ if (ret == 0) {
+ struct smc_local *lp = (struct smc_local *)global_dev->priv;
++#ifdef PM_DEBUG
++ lp->pm = pm_register(PM_SYS_UNKNOWN, 0x73393178, smc_pm_callback, "smc91x");
++#else
+ lp->pm = pm_register(PM_SYS_UNKNOWN, 0x73393178, smc_pm_callback);
++#endif
+ }
+ #endif
+
+--- linux-2.4.21/drivers/net/smc91x.h~ramses-smc91x
++++ linux-2.4.21/drivers/net/smc91x.h
+@@ -79,6 +79,11 @@
+ #include <asm/arch/ramses.h>
+ #define SMC_IOADDR (RAMSES_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
+--- linux-2.4.21/drivers/net/wireless/hermes.c~orinoco013e
++++ linux-2.4.21/drivers/net/wireless/hermes.c
+@@ -52,7 +52,6 @@
+
+ #include "hermes.h"
+
+-static char version[] __initdata = "hermes.c: 4 Dec 2002 David Gibson <hermes@gibson.dropbear.id.au>";
+ MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
+ MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
+ #ifdef MODULE_LICENSE
+@@ -226,7 +225,8 @@
+ * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
+ *
+ * Callable from any context, but locking is your problem. */
+-int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp)
++int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
++ hermes_response_t *resp)
+ {
+ int err;
+ int k;
+@@ -469,13 +469,17 @@
+
+ err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
+ if (err)
+- goto out;
++ return err;
+
+ err = hermes_bap_seek(hw, bap, rid, 0);
+ if (err)
+- goto out;
++ return err;
+
+ rlength = hermes_read_reg(hw, dreg);
++
++ if (! rlength)
++ return -ENOENT;
++
+ rtype = hermes_read_reg(hw, dreg);
+
+ if (length)
+@@ -495,8 +499,7 @@
+ nwords = min((unsigned)rlength - 1, bufsize / 2);
+ hermes_read_words(hw, dreg, buf, nwords);
+
+- out:
+- return err;
++ return 0;
+ }
+
+ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
+@@ -511,7 +514,7 @@
+
+ err = hermes_bap_seek(hw, bap, rid, 0);
+ if (err)
+- goto out;
++ return err;
+
+ hermes_write_reg(hw, dreg, length);
+ hermes_write_reg(hw, dreg, rid);
+@@ -523,7 +526,6 @@
+ err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
+ rid, NULL);
+
+- out:
+ return err;
+ }
+
+@@ -539,9 +541,12 @@
+
+ static int __init init_hermes(void)
+ {
+- printk(KERN_DEBUG "%s\n", version);
+-
+ return 0;
+ }
+
++static void __exit exit_hermes(void)
++{
++}
++
+ module_init(init_hermes);
++module_exit(exit_hermes);
+--- linux-2.4.21/drivers/net/wireless/hermes.h~orinoco013e
++++ linux-2.4.21/drivers/net/wireless/hermes.h
+@@ -250,7 +250,6 @@
+ u16 scanreason; /* ??? */
+ struct hermes_scan_apinfo aps[35]; /* Scan result */
+ } __attribute__ ((packed));
+-
+ #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
+ #define HERMES_LINKSTATUS_CONNECTED (0x0001)
+ #define HERMES_LINKSTATUS_DISCONNECTED (0x0002)
+@@ -278,7 +277,7 @@
+
+ /* Basic control structure */
+ typedef struct hermes {
+- ulong iobase;
++ unsigned long iobase;
+ int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */
+ #define HERMES_IO 1
+ #define HERMES_MEM 0
+@@ -368,7 +367,7 @@
+ if (hw->io_space) {
+ insw(hw->iobase + off, buf, count);
+ } else {
+- int i;
++ unsigned i;
+ u16 *p;
+
+ /* This needs to *not* byteswap (like insw()) but
+@@ -388,7 +387,7 @@
+ if (hw->io_space) {
+ outsw(hw->iobase + off, buf, count);
+ } else {
+- int i;
++ unsigned i;
+ const u16 *p;
+
+ /* This needs to *not* byteswap (like outsw()) but
+@@ -398,6 +397,21 @@
+ for (i = 0, p = buf; i < count; i++) {
+ writew(le16_to_cpu(*p++), hw->iobase + off);
+ }
++ }
++}
++
++static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count)
++{
++ unsigned i;
++
++ off = off << hw->reg_spacing;;
++
++ if (hw->io_space) {
++ for (i = 0; i < count; i++)
++ outw(0, hw->iobase + off);
++ } else {
++ for (i = 0; i < count; i++)
++ writew(0, hw->iobase + off);
+ }
+ }
+
+--- linux-2.4.21/drivers/net/wireless/ieee802_11.h~orinoco013e
++++ linux-2.4.21/drivers/net/wireless/ieee802_11.h
+@@ -9,6 +9,8 @@
+ bytes is allowed, which is a bit confusing, I suspect this
+ represents the 2304 bytes of real data, plus a possible 8 bytes of
+ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
++
++
+ #define IEEE802_11_HLEN 30
+ #define IEEE802_11_FRAME_LEN (IEEE802_11_DATA_LEN + IEEE802_11_HLEN)
+
+--- linux-2.4.21/drivers/net/wireless/orinoco.c~orinoco013e
++++ linux-2.4.21/drivers/net/wireless/orinoco.c
+@@ -1,4 +1,4 @@
+-/* orinoco.c 0.13b - (formerly known as dldwd_cs.c and orinoco_cs.c)
++/* orinoco.c 0.13e - (formerly known as dldwd_cs.c and orinoco_cs.c)
+ *
+ * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
+ * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
+@@ -117,7 +117,7 @@
+ * o Init of priv->tx_rate_ctrl in firmware specific section.
+ * o Prism2/Symbol rate, upto should be 0xF and not 0x15. Doh !
+ * o Spectrum card always need cor_reset (for every reset)
+- * o Fix cor_reset to not loose bit 7 in the register
++ * o Fix cor_reset to not lose bit 7 in the register
+ * o flush_stale_links to remove zombie Pcmcia instances
+ * o Ack previous hermes event before reset
+ * Me (with my little hands)
+@@ -289,7 +289,7 @@
+ * which are used as the dev->open, dev->stop, priv->reset
+ * callbacks if none are specified when alloc_orinocodev() is
+ * called.
+- * o Removed orinoco_plx_interupt() and orinoco_pci_interrupt().
++ * o Removed orinoco_plx_interrupt() and orinoco_pci_interrupt().
+ * They didn't do anything.
+ *
+ * v0.12 -> v0.12a - 4 Jul 2002 - David Gibson
+@@ -345,13 +345,54 @@
+ * we are connected (avoids cofusing the firmware), and only
+ * give LINKSTATUS printk()s if the status has changed.
+ *
++ * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson
++ * o Cleanup: use dev instead of priv in various places.
++ * o Bug fix: Don't ReleaseConfiguration on RESET_PHYSICAL event
++ * if we're in the middle of a (driver initiated) hard reset.
++ * o Bug fix: ETH_ZLEN is supposed to include the header
++ * (Dionysus Blazakis & Manish Karir)
++ * o Convert to using workqueues instead of taskqueues (and
++ * backwards compatibility macros for pre 2.5.41 kernels).
++ * o Drop redundant (I think...) MOD_{INC,DEC}_USE_COUNT in
++ * airport.c
++ * o New orinoco_tmd.c init module from Joerg Dorchain for
++ * TMD7160 based PCI to PCMCIA bridges (similar to
++ * orinoco_plx.c).
++ *
++ * v0.13c -> v0.13d - 22 Apr 2003 - David Gibson
++ * o Make hw_unavailable a counter, rather than just a flag, this
++ * is necessary to avoid some races (such as a card being
++ * removed in the middle of orinoco_reset().
++ * o Restore Release/RequestConfiguration in the PCMCIA event handler
++ * when dealing with a driver initiated hard reset. This is
++ * necessary to prevent hangs due to a spurious interrupt while
++ * the reset is in progress.
++ * o Clear the 802.11 header when transmitting, even though we
++ * don't use it. This fixes a long standing bug on some
++ * firmwares, which seem to get confused if that isn't done.
++ * o Be less eager to de-encapsulate SNAP frames, only do so if
++ * the OUI is 00:00:00 or 00:00:f8, leave others alone. The old
++ * behaviour broke CDP (Cisco Discovery Protocol).
++ * o Use dev instead of priv for free_irq() as well as
++ * request_irq() (oops).
++ * o Attempt to reset rather than giving up if we get too many
++ * IRQs.
++ * o Changed semantics of __orinoco_down() so it can be called
++ * safely with hw_unavailable set. It also now clears the
++ * linkstatus (since we're going to have to reassociate).
++ *
++ * v0.13d -> v0.13e - 12 May 2003 - David Gibson
++ * o Support for post-2.5.68 return values from irq handler.
++ * o Fixed bug where underlength packets would be double counted
++ * in the rx_dropped statistics.
++ * o Provided a module parameter to suppress linkstatus messages.
++ *
+ * TODO
+-
+ * o New wireless extensions API (patch from Moustafa
+- * Youssef, updated by Jim Carter).
+- * o Fix PCMCIA hard resets with pcmcia-cs.
++ * Youssef, updated by Jim Carter and Pavel Roskin).
+ * o Handle de-encapsulation within network layer, provide 802.11
+ * headers (patch from Thomas 'Dent' Mirlacher)
++ * o RF monitor mode support
+ * o Fix possible races in SPY handling.
+ * o Disconnect wireless extensions from fundamental configuration.
+ * o (maybe) Software WEP support (patch from Stano Meduna).
+@@ -373,27 +414,27 @@
+ * flag after taking the lock, and if it is set, give up on whatever
+ * they are doing and drop the lock again. The orinoco_lock()
+ * function handles this (it unlocks and returns -EBUSY if
+- * hw_unavailable is true). */
++ * hw_unavailable is non-zero). */
+
+ #include <linux/config.h>
+
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+-#include <linux/sched.h>
+ #include <linux/ptrace.h>
+ #include <linux/slab.h>
+ #include <linux/string.h>
+ #include <linux/timer.h>
+ #include <linux/ioport.h>
+-#include <asm/uaccess.h>
+-#include <asm/io.h>
+-#include <asm/system.h>
+ #include <linux/netdevice.h>
+ #include <linux/if_arp.h>
+ #include <linux/etherdevice.h>
+ #include <linux/wireless.h>
+
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/system.h>
++
+ #include "hermes.h"
+ #include "hermes_rid.h"
+ #include "orinoco.h"
+@@ -416,6 +457,9 @@
+ EXPORT_SYMBOL(orinoco_debug);
+ #endif
+
++static int suppress_linkstatus; /* = 0 */
++MODULE_PARM(suppress_linkstatus, "i");
++
+ /********************************************************************/
+ /* Compile time configuration and compatibility stuff */
+ /********************************************************************/
+@@ -443,8 +487,10 @@
+ #define USER_BAP 0
+ #define IRQ_BAP 1
+ #define MAX_IRQLOOPS_PER_IRQ 10
+-#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of how many events the
+- device could legitimately generate */
++#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of
++ * how many events the
++ * device could
++ * legitimately generate */
+ #define SMALL_KEY_SIZE 5
+ #define LARGE_KEY_SIZE 13
+ #define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */
+@@ -480,8 +526,8 @@
+ {10, 1, 1, 1},
+ {20, 0, 2, 2},
+ {20, 1, 6, 3},
+- {55, 0, 4, 4},
+- {55, 1, 7, 7},
++ {55, 0, 4, 4},
++ {55, 1, 7, 7},
+ {110, 0, 5, 8},
+ };
+ #define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0]))
+@@ -522,7 +568,7 @@
+
+ /* Hardware control routines */
+
+-static int __orinoco_program_rids(struct orinoco_private *priv);
++static int __orinoco_program_rids(struct net_device *dev);
+
+ static int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
+ static int __orinoco_hw_setup_wep(struct orinoco_private *priv);
+@@ -535,37 +581,17 @@
+ static void __orinoco_set_multicast_list(struct net_device *dev);
+
+ /* Interrupt handling routines */
+-static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw);
+-static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw);
+-static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw);
+-static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw);
+-static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw);
+-static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw);
+-static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw);
+-static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw);
++static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw);
++static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw);
++static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw);
++static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw);
++static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw);
++static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw);
++static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw);
++static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw);
+
+ /* ioctl() routines */
+-static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);
+-static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);
+-static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);
+-static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq);
+-static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq);
+-static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq);
+-static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq);
+-static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq);
+-static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq);
+-static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq);
+-static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq);
+-static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq);
+-static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq);
+-static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *frq);
+-static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *frq);
+-static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq);
+-static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq);
+-static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);
+-static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);
+-
+-static int orinoco_debug_dump_recs(struct orinoco_private *priv);
++static int orinoco_debug_dump_recs(struct net_device *dev);
+
+ /********************************************************************/
+ /* Function prototypes */
+@@ -577,7 +603,7 @@
+ struct hermes *hw = &priv->hw;
+ int err;
+
+- err = __orinoco_program_rids(priv);
++ err = __orinoco_program_rids(dev);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d configuring card\n",
+ dev->name, err);
+@@ -606,14 +632,25 @@
+
+ netif_stop_queue(dev);
+
+- err = hermes_disable_port(hw, 0);
+- if (err) {
+- printk(KERN_ERR "%s: Error %d disabling MAC port\n",
+- dev->name, err);
+- return err;
++ if (! priv->hw_unavailable) {
++ if (! priv->broken_disableport) {
++ err = hermes_disable_port(hw, 0);
++ if (err) {
++ /* Some firmwares (e.g. Intersil 1.3.x) seem
++ * to have problems disabling the port, oh
++ * well, too bad. */
++ printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
++ dev->name, err);
++ priv->broken_disableport = 1;
++ }
++ }
++ hermes_set_irqmask(hw, 0);
++ hermes_write_regn(hw, EVACK, 0xffff);
+ }
+- hermes_set_irqmask(hw, 0);
+- hermes_write_regn(hw, EVACK, 0xffff);
++
++ /* firmware will have to reassociate */
++ priv->last_linkstatus = 0xffff;
++ priv->connected = 0;
+
+ return 0;
+ }
+@@ -656,38 +693,38 @@
+ if (err)
+ return err;
+
+- priv->open = 1;
+-
+ err = __orinoco_up(dev);
+
++ if (! err)
++ priv->open = 1;
++
+ orinoco_unlock(priv, &flags);
+
+ return err;
+ }
+
+-static int orinoco_stop(struct net_device *dev)
++int orinoco_stop(struct net_device *dev)
+ {
+ struct orinoco_private *priv = dev->priv;
+ int err = 0;
+
+ /* We mustn't use orinoco_lock() here, because we need to be
+- able to close the interface, even if hw_unavailable is set
++ able to close the interface even if hw_unavailable is set
+ (e.g. as we're released after a PC Card removal) */
+ spin_lock_irq(&priv->lock);
+
+ priv->open = 0;
+
+- if (! priv->hw_unavailable)
+- err = __orinoco_down(dev);
++ err = __orinoco_down(dev);
+
+ spin_unlock_irq(&priv->lock);
+
+ return err;
+ }
+
+-static int __orinoco_program_rids(struct orinoco_private *priv)
++static int __orinoco_program_rids(struct net_device *dev)
+ {
+- struct net_device *dev = priv->ndev;
++ struct orinoco_private *priv = dev->priv;
+ hermes_t *hw = &priv->hw;
+ int err;
+ struct hermes_idstring idbuf;
+@@ -873,51 +910,84 @@
+ }
+
+ /* xyzzy */
+-static int orinoco_reconfigure(struct orinoco_private *priv)
++static int orinoco_reconfigure(struct net_device *dev)
+ {
++ struct orinoco_private *priv = dev->priv;
+ struct hermes *hw = &priv->hw;
+ unsigned long flags;
+ int err = 0;
+
+- orinoco_lock(priv, &flags);
++ if (priv->broken_disableport) {
++ schedule_work(&priv->reset_work);
++ return 0;
++ }
++
++ err = orinoco_lock(priv, &flags);
++ if (err)
++ return err;
+
++
+ err = hermes_disable_port(hw, 0);
+ if (err) {
+- printk(KERN_ERR "%s: Unable to disable port in orinco_reconfigure()\n",
+- priv->ndev->name);
++ printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n",
++ dev->name);
++ priv->broken_disableport = 1;
+ goto out;
+ }
+
+- err = __orinoco_program_rids(priv);
+- if (err)
++ err = __orinoco_program_rids(dev);
++ if (err) {
++ printk(KERN_WARNING "%s: Unable to reconfigure card\n",
++ dev->name);
+ goto out;
++ }
+
+ err = hermes_enable_port(hw, 0);
+ if (err) {
+- printk(KERN_ERR "%s: Unable to enable port in orinco_reconfigure()\n",
+- priv->ndev->name);
++ printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
++ dev->name);
+ goto out;
+ }
+
+ out:
++ if (err) {
++ printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
++ schedule_work(&priv->reset_work);
++ err = 0;
++ }
++
+ orinoco_unlock(priv, &flags);
+ return err;
+
+ }
+
+ /* This must be called from user context, without locks held - use
+- * schedule_task() */
++ * schedule_work() */
+ static void orinoco_reset(struct net_device *dev)
+ {
+ struct orinoco_private *priv = dev->priv;
++ struct hermes *hw = &priv->hw;
+ int err;
+ unsigned long flags;
+
+ err = orinoco_lock(priv, &flags);
+ if (err)
++ /* When the hardware becomes available again, whatever
++ * detects that is responsible for re-initializing
++ * it. So no need for anything further*/
+ return;
+
+- priv->hw_unavailable = 1;
++ netif_stop_queue(dev);
++
++ /* Shut off interrupts. Depending on what state the hardware
++ * is in, this might not work, but we'll try anyway */
++ hermes_set_irqmask(hw, 0);
++ hermes_write_regn(hw, EVACK, 0xffff);
++
++ priv->hw_unavailable++;
++ priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
++ priv->connected = 0;
++
+ orinoco_unlock(priv, &flags);
+
+ if (priv->hard_reset)
+@@ -936,18 +1006,22 @@
+ return;
+ }
+
+- spin_lock_irqsave(&priv->lock, flags);
++ spin_lock_irq(&priv->lock); /* This has to be called from user context */
+
+- priv->hw_unavailable = 0;
++ priv->hw_unavailable--;
+
+- err = __orinoco_up(dev);
+- if (err) {
+- printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
+- dev->name, err);
+- } else
+- dev->trans_start = jiffies;
++ /* priv->open or priv->hw_unavailable might have changed while
++ * we dropped the lock */
++ if (priv->open && (! priv->hw_unavailable)) {
++ err = __orinoco_up(dev);
++ if (err) {
++ printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
++ dev->name, err);
++ } else
++ dev->trans_start = jiffies;
++ }
+
+- orinoco_unlock(priv, &flags);
++ spin_unlock_irq(&priv->lock);
+
+ return;
+ }
+@@ -979,10 +1053,18 @@
+ }
+ }
+
++/* Does the frame have a SNAP header indicating it should be
++ * de-encapsulated to Ethernet-II? */
+ static inline int
+-is_snap(struct header_struct *hdr)
++is_ethersnap(struct header_struct *hdr)
+ {
+- return (hdr->dsap == 0xAA) && (hdr->ssap == 0xAA) && (hdr->ctrl == 0x3);
++ /* We de-encapsulate all packets which, a) have SNAP headers
++ * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
++ * and where b) the OUI of the SNAP header is 00:00:00 or
++ * 00:00:f8 - we need both because different APs appear to use
++ * different OUIs for some reason */
++ return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0)
++ && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) );
+ }
+
+ static void
+@@ -1140,7 +1222,8 @@
+ return 0;
+ }
+
+-static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN])
++static int orinoco_hw_get_bssid(struct orinoco_private *priv,
++ char buf[ETH_ALEN])
+ {
+ hermes_t *hw = &priv->hw;
+ int err = 0;
+@@ -1159,7 +1242,7 @@
+ }
+
+ static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
+- char buf[IW_ESSID_MAX_SIZE+1])
++ char buf[IW_ESSID_MAX_SIZE+1])
+ {
+ hermes_t *hw = &priv->hw;
+ int err = 0;
+@@ -1236,9 +1319,8 @@
+ }
+
+ if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
+- struct net_device *dev = priv->ndev;
+-
+- printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel);
++ printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
++ priv->ndev->name, channel);
+ err = -EBUSY;
+ goto out;
+
+@@ -1253,8 +1335,8 @@
+ return err ? err : freq;
+ }
+
+-static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates,
+- s32 *rates, int max)
++static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
++ int *numrates, s32 *rates, int max)
+ {
+ hermes_t *hw = &priv->hw;
+ struct hermes_idstring list;
+@@ -1287,9 +1369,6 @@
+ }
+
+ #if 0
+-#ifndef ORINOCO_DEBUG
+-static inline void show_rx_frame(struct orinoco_rxframe_hdr *frame) {}
+-#else
+ static void show_rx_frame(struct orinoco_rxframe_hdr *frame)
+ {
+ printk(KERN_DEBUG "RX descriptor:\n");
+@@ -1346,17 +1425,16 @@
+ frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]);
+ printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype);
+ }
+-#endif
+-#endif
++#endif /* 0 */
+
+ /*
+ * Interrupt handler
+ */
+-void orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+- struct orinoco_private *priv = (struct orinoco_private *) dev_id;
++ struct net_device *dev = (struct net_device *)dev_id;
++ struct orinoco_private *priv = dev->priv;
+ hermes_t *hw = &priv->hw;
+- struct net_device *dev = priv->ndev;
+ int count = MAX_IRQLOOPS_PER_IRQ;
+ u16 evstat, events;
+ /* These are used to detect a runaway interrupt situation */
+@@ -1367,12 +1445,17 @@
+ unsigned long flags;
+
+ if (orinoco_lock(priv, &flags) != 0) {
+- /* If hw is unavailable */
+- return;
++ /* If hw is unavailable - we don't know if the irq was
++ * for us or not */
++ return IRQ_HANDLED;
+ }
+
+ evstat = hermes_read_regn(hw, EVSTAT);
+ events = evstat & hw->inten;
++ if (! events) {
++ orinoco_unlock(priv, &flags);
++ return IRQ_NONE;
++ }
+
+ if (jiffies != last_irq_jiffy)
+ loops_this_jiffy = 0;
+@@ -1380,11 +1463,11 @@
+
+ while (events && count--) {
+ if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
+- printk(KERN_CRIT "%s: IRQ handler is looping too \
+-much! Shutting down.\n",
+- dev->name);
+- /* Perform an emergency shutdown */
++ printk(KERN_WARNING "%s: IRQ handler is looping too "
++ "much! Resetting.\n", dev->name);
++ /* Disable interrupts for now */
+ hermes_set_irqmask(hw, 0);
++ schedule_work(&priv->reset_work);
+ break;
+ }
+
+@@ -1395,21 +1478,21 @@
+ }
+
+ if (events & HERMES_EV_TICK)
+- __orinoco_ev_tick(priv, hw);
++ __orinoco_ev_tick(dev, hw);
+ if (events & HERMES_EV_WTERR)
+- __orinoco_ev_wterr(priv, hw);
++ __orinoco_ev_wterr(dev, hw);
+ if (events & HERMES_EV_INFDROP)
+- __orinoco_ev_infdrop(priv, hw);
++ __orinoco_ev_infdrop(dev, hw);
+ if (events & HERMES_EV_INFO)
+- __orinoco_ev_info(priv, hw);
++ __orinoco_ev_info(dev, hw);
+ if (events & HERMES_EV_RX)
+- __orinoco_ev_rx(priv, hw);
++ __orinoco_ev_rx(dev, hw);
+ if (events & HERMES_EV_TXEXC)
+- __orinoco_ev_txexc(priv, hw);
++ __orinoco_ev_txexc(dev, hw);
+ if (events & HERMES_EV_TX)
+- __orinoco_ev_tx(priv, hw);
++ __orinoco_ev_tx(dev, hw);
+ if (events & HERMES_EV_ALLOC)
+- __orinoco_ev_alloc(priv, hw);
++ __orinoco_ev_alloc(dev, hw);
+
+ hermes_write_regn(hw, EVACK, events);
+
+@@ -1418,30 +1501,34 @@
+ };
+
+ orinoco_unlock(priv, &flags);
++ return IRQ_HANDLED;
+ }
+
+-static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw)
++static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw)
+ {
+- printk(KERN_DEBUG "%s: TICK\n", priv->ndev->name);
++ printk(KERN_DEBUG "%s: TICK\n", dev->name);
+ }
+
+-static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw)
++static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
+ {
+ /* This seems to happen a fair bit under load, but ignoring it
+ seems to work fine...*/
+ printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
+- priv->ndev->name);
++ dev->name);
+ }
+
+-static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw)
++static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
+ {
+- printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev->name);
++ printk(KERN_WARNING "%s: Information frame lost.\n", dev->name);
+ }
+
+ static void print_linkstatus(struct net_device *dev, u16 status)
+ {
+ char * s;
+
++ if (suppress_linkstatus)
++ return;
++
+ switch (status) {
+ case HERMES_LINKSTATUS_NOT_CONNECTED:
+ s = "Not Connected";
+@@ -1472,9 +1559,9 @@
+ dev->name, s, status);
+ }
+
+-static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw)
++static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
+ {
+- struct net_device *dev = priv->ndev;
++ struct orinoco_private *priv = dev->priv;
+ u16 infofid;
+ struct {
+ u16 len;
+@@ -1573,9 +1660,9 @@
+ }
+ }
+
+-static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw)
++static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
+ {
+- struct net_device *dev = priv->ndev;
++ struct orinoco_private *priv = dev->priv;
+ struct net_device_stats *stats = &priv->stats;
+ struct iw_statistics *wstats = &priv->wstats;
+ struct sk_buff *skb = NULL;
+@@ -1664,14 +1751,13 @@
+ * So, check ourselves */
+ if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
+ ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
+- is_snap(&hdr)) {
++ is_ethersnap(&hdr)) {
+ /* These indicate a SNAP within 802.2 LLC within
+ 802.11 frame which we'll need to de-encapsulate to
+ the original EthernetII frame. */
+
+ if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
+ stats->rx_length_errors++;
+- stats->rx_dropped++;
+ goto drop;
+ }
+
+@@ -1726,9 +1812,9 @@
+ return;
+ }
+
+-static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw)
++static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
+ {
+- struct net_device *dev = priv->ndev;
++ struct orinoco_private *priv = dev->priv;
+ struct net_device_stats *stats = &priv->stats;
+ u16 fid = hermes_read_regn(hw, TXCOMPLFID);
+ struct hermes_tx_descriptor desc;
+@@ -1752,8 +1838,9 @@
+ hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+ }
+
+-static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw)
++static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
+ {
++ struct orinoco_private *priv = dev->priv;
+ struct net_device_stats *stats = &priv->stats;
+
+ stats->tx_packets++;
+@@ -1761,9 +1848,10 @@
+ hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+ }
+
+-static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw)
++static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
+ {
+- struct net_device *dev = priv->ndev;
++ struct orinoco_private *priv = dev->priv;
++
+ u16 fid = hermes_read_regn(hw, ALLOCFID);
+
+ if (fid != priv->txfid) {
+@@ -1945,7 +2033,7 @@
+
+ TRACE_ENTER(dev->name);
+
+- /* No need to lock, the resetting flag is already set in
++ /* No need to lock, the hw_unavailable flag is already set in
+ * alloc_orinocodev() */
+ priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
+
+@@ -2081,8 +2169,6 @@
+ priv->wep_on = 0;
+ priv->tx_key = 0;
+
+- priv->hw_unavailable = 0;
+-
+ err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+ if (err == -EIO) {
+ /* Try workaround for old Symbol firmware bug */
+@@ -2102,6 +2188,12 @@
+ goto out;
+ }
+
++ /* Make the hardware available, as long as it hasn't been
++ * removed elsewhere (e.g. by PCMCIA hot unplug) */
++ spin_lock_irq(&priv->lock);
++ priv->hw_unavailable--;
++ spin_unlock_irq(&priv->lock);
++
+ printk(KERN_DEBUG "%s: ready\n", dev->name);
+
+ out:
+@@ -2267,7 +2359,7 @@
+
+ /* Length of the packet body */
+ /* FIXME: what if the skb is smaller than this? */
+- len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN);
++ len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN);
+
+ eh = (struct ethhdr *)skb->data;
+
+@@ -2281,6 +2373,12 @@
+ goto fail;
+ }
+
++ /* Clear the 802.11 header and data length fields - some
++ * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
++ * if this isn't done. */
++ hermes_clear_words(hw, HERMES_DATA0,
++ HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
++
+ /* Encapsulate Ethernet-II frames */
+ if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */
+ struct header_struct hdr;
+@@ -2362,7 +2460,7 @@
+
+ stats->tx_errors++;
+
+- schedule_task(&priv->timeout_task);
++ schedule_work(&priv->reset_work);
+ }
+
+ static int
+@@ -2532,7 +2630,7 @@
+ }
+
+ err = orinoco_hw_get_bitratelist(priv, &numrates,
+- range.bitrate, IW_MAX_BITRATES);
++ range.bitrate, IW_MAX_BITRATES);
+ if (err)
+ return err;
+ range.num_bitrates = numrates;
+@@ -2799,7 +2897,7 @@
+ erq->flags = 1;
+ erq->length = strlen(essidbuf) + 1;
+ if (erq->pointer)
+- if ( copy_to_user(erq->pointer, essidbuf, erq->length) )
++ if (copy_to_user(erq->pointer, essidbuf, erq->length))
+ return -EFAULT;
+
+ TRACE_EXIT(dev->name);
+@@ -3128,7 +3226,7 @@
+ rrq->value = 5500000;
+ else
+ rrq->value = val * 1000000;
+- break;
++ break;
+ case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
+ case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
+ for (i = 0; i < BITRATE_TABLE_SIZE; i++)
+@@ -3754,7 +3852,7 @@
+
+ printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
+
+- schedule_task(&priv->timeout_task);
++ schedule_work(&priv->reset_work);
+ break;
+
+ case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
+@@ -3827,7 +3925,7 @@
+ break;
+
+ case SIOCIWLASTPRIV:
+- err = orinoco_debug_dump_recs(priv);
++ err = orinoco_debug_dump_recs(dev);
+ if (err)
+ printk(KERN_ERR "%s: Unable to dump records (%d)\n",
+ dev->name, err);
+@@ -3839,7 +3937,7 @@
+ }
+
+ if (! err && changed && netif_running(dev)) {
+- err = orinoco_reconfigure(priv);
++ err = orinoco_reconfigure(dev);
+ }
+
+ TRACE_EXIT(dev->name);
+@@ -3924,7 +4022,7 @@
+ DEBUG_REC(PRIID,WORDS),
+ DEBUG_REC(PRISUPRANGE,WORDS),
+ DEBUG_REC(CFIACTRANGES,WORDS),
+- DEBUG_REC(NICSERNUM,WORDS),
++ DEBUG_REC(NICSERNUM,XSTRING),
+ DEBUG_REC(NICID,WORDS),
+ DEBUG_REC(MFISUPRANGE,WORDS),
+ DEBUG_REC(CFISUPRANGE,WORDS),
+@@ -3961,8 +4059,9 @@
+
+ #define DEBUG_LTV_SIZE 128
+
+-static int orinoco_debug_dump_recs(struct orinoco_private *priv)
++static int orinoco_debug_dump_recs(struct net_device *dev)
+ {
++ struct orinoco_private *priv = dev->priv;
+ hermes_t *hw = &priv->hw;
+ u8 *val8;
+ u16 *val16;
+@@ -4051,6 +4150,7 @@
+ dev->do_ioctl = orinoco_ioctl;
+ dev->change_mtu = orinoco_change_mtu;
+ dev->set_multicast_list = orinoco_set_multicast_list;
++ /* we use the default eth_mac_addr for setting the MAC addr */
+
+ /* Set up default callbacks */
+ dev->open = orinoco_open;
+@@ -4062,7 +4162,7 @@
+ priv->hw_unavailable = 1; /* orinoco_init() must clear this
+ * before anything else touches the
+ * hardware */
+- INIT_TQUEUE(&priv->timeout_task, (void (*)(void *))orinoco_reset, dev);
++ INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
+
+ priv->last_linkstatus = 0xffff;
+ priv->connected = 0;
+@@ -4079,13 +4179,14 @@
+
+ EXPORT_SYMBOL(__orinoco_up);
+ EXPORT_SYMBOL(__orinoco_down);
++EXPORT_SYMBOL(orinoco_stop);
+ EXPORT_SYMBOL(orinoco_reinit_firmware);
+
+ EXPORT_SYMBOL(orinoco_interrupt);
+
+ /* Can't be declared "const" or the whole __initdata section will
+ * become const */
+-static char version[] __initdata = "orinoco.c 0.13b (David Gibson <hermes@gibson.dropbear.id.au> and others)";
++static char version[] __initdata = "orinoco.c 0.13e (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+
+ static int __init init_orinoco(void)
+ {
+--- linux-2.4.21/drivers/net/wireless/orinoco.h~orinoco013e
++++ linux-2.4.21/drivers/net/wireless/orinoco.h
+@@ -11,9 +11,29 @@
+ #include <linux/spinlock.h>
+ #include <linux/netdevice.h>
+ #include <linux/wireless.h>
+-#include <linux/tqueue.h>
++#include <linux/version.h>
+ #include "hermes.h"
+
++/* Workqueue / task queue backwards compatibility stuff */
++
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
++#include <linux/workqueue.h>
++#else
++#include <linux/tqueue.h>
++#define work_struct tq_struct
++#define INIT_WORK INIT_TQUEUE
++#define schedule_work schedule_task
++#endif
++
++/* Interrupt handler backwards compatibility stuff */
++#ifndef IRQ_NONE
++
++#define IRQ_NONE
++#define IRQ_HANDLED
++typedef void irqreturn_t;
++
++#endif
++
+ /* To enable debug messages */
+ //#define ORINOCO_DEBUG 3
+
+@@ -36,13 +56,13 @@
+
+
+ struct orinoco_private {
+- void *card; /* Pointer to card dependant structure */
++ void *card; /* Pointer to card dependent structure */
+ int (*hard_reset)(struct orinoco_private *);
+
+ /* Synchronisation stuff */
+ spinlock_t lock;
+ int hw_unavailable;
+- struct tq_struct timeout_task;
++ struct work_struct reset_work;
+
+ /* driver state */
+ int open;
+@@ -72,6 +92,7 @@
+ int has_sensitivity;
+ int nicbuf_size;
+ u16 channel_mask;
++ int broken_disableport;
+
+ /* Configuration paramaters */
+ u32 iw_mode;
+@@ -111,9 +132,9 @@
+ int (*hard_reset)(struct orinoco_private *));
+ extern int __orinoco_up(struct net_device *dev);
+ extern int __orinoco_down(struct net_device *dev);
+-int orinoco_reinit_firmware(struct net_device *dev);
+-
+-extern void orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs);
++extern int orinoco_stop(struct net_device *dev);
++extern int orinoco_reinit_firmware(struct net_device *dev);
++extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs);
+
+ /********************************************************************/
+ /* Locking and synchronization functions */
+--- linux-2.4.21/drivers/net/wireless/orinoco_cs.c~orinoco013e
++++ linux-2.4.21/drivers/net/wireless/orinoco_cs.c
+@@ -1,4 +1,4 @@
+-/* orinoco_cs.c 0.13b - (formerly known as dldwd_cs.c)
++/* orinoco_cs.c 0.13e - (formerly known as dldwd_cs.c)
+ *
+ * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
+ * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
+@@ -22,11 +22,7 @@
+ #include <linux/ptrace.h>
+ #include <linux/slab.h>
+ #include <linux/string.h>
+-#include <linux/timer.h>
+ #include <linux/ioport.h>
+-#include <asm/uaccess.h>
+-#include <asm/io.h>
+-#include <asm/system.h>
+ #include <linux/netdevice.h>
+ #include <linux/if_arp.h>
+ #include <linux/etherdevice.h>
+@@ -38,7 +34,10 @@
+ #include <pcmcia/cistpl.h>
+ #include <pcmcia/cisreg.h>
+ #include <pcmcia/ds.h>
+-#include <pcmcia/bus_ops.h>
++
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/system.h>
+
+ #include "orinoco.h"
+
+@@ -62,7 +61,7 @@
+
+ /* Some D-Link cards have buggy CIS. They do work at 5v properly, but
+ * don't have any CIS entry for it. This workaround it... */
+-static int ignore_cis_vcc; /* = 0 */
++static int ignore_cis_vcc = 1;
+
+ MODULE_PARM(irq_mask, "i");
+ MODULE_PARM(irq_list, "1-4i");
+@@ -145,8 +144,10 @@
+ /* PCMCIA stuff */
+ /********************************************************************/
+
++/* In 2.5 (as of 2.5.69 at least) there is a cs_error exported which
++ * does this, but it's not in 2.4 so we do our own for now. */
+ static void
+-cs_error(client_handle_t handle, int func, int ret)
++orinoco_cs_error(client_handle_t handle, int func, int ret)
+ {
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+@@ -202,6 +203,7 @@
+ link->priv = dev;
+
+ /* Initialize the dev_link_t structure */
++ init_timer(&link->release);
+ link->release.function = &orinoco_cs_release;
+ link->release.data = (u_long) link;
+
+@@ -240,7 +242,7 @@
+
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != CS_SUCCESS) {
+- cs_error(link->handle, RegisterClient, ret);
++ orinoco_cs_error(link->handle, RegisterClient, ret);
+ orinoco_cs_detach(link);
+ return NULL;
+ }
+@@ -269,19 +271,12 @@
+ return;
+ }
+
+- /*
+- If the device is currently configured and active, we won't
+- actually delete it yet. Instead, it is marked so that when
+- the release() function is called, that will trigger a proper
+- detach().
+- */
+ if (link->state & DEV_CONFIG) {
+-#ifdef PCMCIA_DEBUG
+- printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' "
+- "still locked\n", link->dev->dev_name);
+-#endif
+- link->state |= DEV_STALE_LINK;
+- return;
++ orinoco_cs_release((u_long)link);
++ if (link->state & DEV_CONFIG) {
++ link->state |= DEV_STALE_LINK;
++ return;
++ }
+ }
+
+ /* Break the link with Card Services */
+@@ -368,7 +363,7 @@
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ while (1) {
+ cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+- cistpl_cftable_entry_t dflt = { index: 0 };
++ cistpl_cftable_entry_t dflt = { .index = 0 };
+
+ CFG_CHECK(GetTupleData, handle, &tuple);
+ CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+@@ -472,7 +467,7 @@
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+
+ link->irq.Handler = orinoco_interrupt;
+- link->irq.Instance = priv;
++ link->irq.Instance = dev;
+
+ CS_CHECK(RequestIRQ, link->handle, &link->irq);
+ }
+@@ -532,7 +527,7 @@
+ return;
+
+ cs_failed:
+- cs_error(link->handle, last_fn, last_ret);
++ orinoco_cs_error(link->handle, last_fn, last_ret);
+
+ failed:
+ orinoco_cs_release((u_long) link);
+@@ -549,18 +544,13 @@
+ dev_link_t *link = (dev_link_t *) arg;
+ struct net_device *dev = link->priv;
+ struct orinoco_private *priv = dev->priv;
++ unsigned long flags;
+
+- /*
+- If the device is currently in use, we won't release until it
+- is actually closed, because until then, we can't be sure that
+- no one will try to access the device or its data structures.
+- */
+- if (priv->open) {
+- DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n",
+- link->dev->dev_name);
+- link->state |= DEV_STALE_CONFIG;
+- return;
+- }
++ /* We're committed to taking the device away now, so mark the
++ * hardware as unavailable */
++ spin_lock_irqsave(&priv->lock, flags);
++ priv->hw_unavailable++;
++ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Don't bother checking to see if these succeed or not */
+ CardServices(ReleaseConfiguration, link->handle);
+@@ -593,14 +583,9 @@
+ orinoco_lock(priv, &flags);
+
+ netif_device_detach(dev);
+- priv->hw_unavailable = 1;
++ priv->hw_unavailable++;
+
+ orinoco_unlock(priv, &flags);
+-
+-/* if (link->open) */
+-/* orinoco_cs_stop(dev); */
+-
+- mod_timer(&link->release, jiffies + HZ / 20);
+ }
+ break;
+
+@@ -619,13 +604,8 @@
+ a better way, short of rewriting the PCMCIA
+ layer to not suck :-( */
+ if (! test_bit(0, &card->hard_reset_in_progress)) {
+- err = orinoco_lock(priv, &flags);
+- if (err) {
+- printk(KERN_ERR "%s: hw_unavailable on SUSPEND/RESET_PHYSICAL\n",
+- dev->name);
+- break;
+- }
+-
++ spin_lock_irqsave(&priv->lock, flags);
++
+ err = __orinoco_down(dev);
+ if (err)
+ printk(KERN_WARNING "%s: %s: Error %d downing interface\n",
+@@ -634,9 +614,9 @@
+ err);
+
+ netif_device_detach(dev);
+- priv->hw_unavailable = 1;
+-
+- orinoco_unlock(priv, &flags);
++ priv->hw_unavailable++;
++
++ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ CardServices(ReleaseConfiguration, link->handle);
+@@ -653,10 +633,6 @@
+ CardServices(RequestConfiguration, link->handle,
+ &link->conf);
+
+- /* If we're only getting these events because
+- of the ResetCard in the hard reset, we
+- don't need to do anything - orinoco_reset()
+- will handle reinitialization. */
+ if (! test_bit(0, &card->hard_reset_in_progress)) {
+ err = orinoco_reinit_firmware(dev);
+ if (err) {
+@@ -668,9 +644,9 @@
+ spin_lock_irqsave(&priv->lock, flags);
+
+ netif_device_attach(dev);
+- priv->hw_unavailable = 0;
++ priv->hw_unavailable--;
+
+- if (priv->open) {
++ if (priv->open && ! priv->hw_unavailable) {
+ err = __orinoco_up(dev);
+ if (err)
+ printk(KERN_ERR "%s: Error %d restarting card\n",
+@@ -678,7 +654,7 @@
+
+ }
+
+- orinoco_unlock(priv, &flags);
++ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ }
+ break;
+@@ -693,7 +669,7 @@
+
+ /* Can't be declared "const" or the whole __initdata section will
+ * become const */
+-static char version[] __initdata = "orinoco_cs.c 0.13b (David Gibson <hermes@gibson.dropbear.id.au> and others)";
++static char version[] __initdata = "orinoco_cs.c 0.13e (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+
+ static int __init
+ init_orinoco_cs(void)
+@@ -722,7 +698,6 @@
+ if (dev_list)
+ DEBUG(0, "orinoco_cs: Removing leftover devices.\n");
+ while (dev_list != NULL) {
+- del_timer(&dev_list->release);
+ if (dev_list->state & DEV_CONFIG)
+ orinoco_cs_release((u_long) dev_list);
+ orinoco_cs_detach(dev_list);
+--- linux-2.4.21/drivers/pcmcia/pxa/Makefile~ramses-pcmcia
++++ linux-2.4.21/drivers/pcmcia/pxa/Makefile
+@@ -12,6 +12,7 @@
+ obj-$(CONFIG_ARCH_PXA_IDP) += pxa_idp.o
+ obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o
+ obj-$(CONFIG_ARCH_PXA_CERF) += ../sa1100_cerf.o
++obj-$(CONFIG_ARCH_RAMSES) += ramses.o
+
+ obj-m := $(O_TARGET)
+
+--- linux-2.4.21/drivers/pcmcia/pxa/pxa.c~pxa-pcmcia
++++ linux-2.4.21/drivers/pcmcia/pxa/pxa.c
+@@ -187,7 +187,6 @@
+ 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);
+
+@@ -240,6 +239,8 @@
+ pcmcia_low_level=&pxa_idp_pcmcia_ops;
+ } else if( machine_is_pxa_cerf()){
+ pcmcia_low_level=&cerf_pcmcia_ops;
++ } else if( machine_is_ramses()){
++ pcmcia_low_level=&ramses_pcmcia_ops;
+ } else if (machine_is_trizeps2()){
+ #ifdef CONFIG_ARCH_TRIZEPS2
+ pcmcia_low_level=&trizeps2_pcmcia_ops;
+@@ -835,7 +836,7 @@
+ static int pxa_pcmcia_set_io_map(unsigned int sock,
+ struct pccard_io_map *map){
+ unsigned int clock, speed;
+- unsigned long mecr, start;
++ unsigned long start;
+
+ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+
+@@ -941,7 +942,7 @@
+ static int pxa_pcmcia_set_mem_map(unsigned int sock,
+ struct pccard_mem_map *map){
+ unsigned int clock, speed;
+- unsigned long mecr, start;
++ unsigned long start;
+
+ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
+
+@@ -1076,7 +1077,6 @@
+ 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 ":"",
+--- linux-2.4.21/drivers/pcmcia/pxa/pxa.h~ramses-pcmcia
++++ linux-2.4.21/drivers/pcmcia/pxa/pxa.h
+@@ -228,6 +228,7 @@
+ 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 ramses_pcmcia_ops;
+ extern struct pcmcia_low_level trizeps2_pcmcia_ops;
+
+ #endif /* !defined(_PCMCIA_PXA_H) */
+--- /dev/null
++++ linux-2.4.21/drivers/pcmcia/pxa/ramses.c
+@@ -0,0 +1,223 @@
++/*
++ * linux/drivers/pcmcia/pxa/ramses.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) 2003 M&N Logistik-Lösungen Online GmbH
++ *
++ * Platform specific routines for the Ramses, based on those
++ * first done for the Lubbock and PXA IDP.
++ *
++ */
++
++#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
++ramses_pcmcia_init(struct pcmcia_init *init)
++{
++ int return_val = 0;
++
++ /* Set PCMCIA Socket 0 power to standby mode.
++ * RAMSES has dedicated CPLD pins for all this stuff :-)
++ */
++
++ /* both slots disabled, reset NOT active */
++ RAMSES_CPLD_PCCARD_EN = PCC0_ENABLE | PCC1_ENABLE;
++
++ RAMSES_CPLD_PCCARD_PWR = 0; //all power to both slots off
++ //GPDR(IRQ_TO_GPIO_2_80(CFCARD_CD_VALID)) &= ~GPIO_bit(IRQ_TO_GPIO_2_80(CFCARD_CD_VALID));
++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(CFCARD_CD_VALID), GPIO_BOTH_EDGES);
++ //GPDR(IRQ_TO_GPIO_2_80(CFCARD_RDYINT)) &= ~GPIO_bit(IRQ_TO_GPIO_2_80(CFCARD_RDYINT));
++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(CFCARD_RDYINT), GPIO_FALLING_EDGE);
++
++ return_val +=
++ request_irq(CFCARD_CD_VALID, init->handler, SA_INTERRUPT,
++ "CF-Card CD", NULL);
++
++ if (return_val < 0) {
++ return -1;
++ }
++
++ return 2;
++}
++
++static int
++ramses_pcmcia_shutdown(void)
++{
++
++ free_irq(CFCARD_CD_VALID, NULL);
++
++ RAMSES_CPLD_PCCARD_EN = 0x03; //disable slots
++ udelay(200);
++ RAMSES_CPLD_PCCARD_PWR = 0; //shut off all power
++
++ return 0;
++}
++
++static int
++ramses_pcmcia_socket_state(struct pcmcia_state_array *state_array)
++{
++ unsigned long status;
++ int return_val = 1;
++ int i;
++ volatile unsigned long *stat_regs[2] = {
++ &RAMSES_CPLD_PCCARD0_STATUS,
++ &RAMSES_CPLD_PCCARD1_STATUS
++ };
++
++ if (state_array->size < 2)
++ return -1;
++
++ memset(state_array->state, 0,
++ (state_array->size) * sizeof (struct pcmcia_state));
++
++ for (i = 1; 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;
++ }
++
++ state_array->state[0].detect = 0;
++ state_array->state[0].ready = 0;
++ state_array->state[0].bvd1 = 0;
++ state_array->state[0].bvd2 = 0;
++ state_array->state[0].wrprot = 0;
++ state_array->state[0].vs_3v = 0;
++ state_array->state[0].vs_Xv = 0;
++
++ return return_val;
++}
++
++static int
++ramses_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
++{
++ switch (info->sock) {
++ case 0:
++ //info->irq = PCMCIA_S0_RDYINT;
++ //printk("//hs ramses_pcmcia_get_irq_info called for slot 0\n");
++ break;
++
++ case 1:
++ info->irq = CFCARD_RDYINT;
++ break;
++
++ default:
++ return -1;
++ }
++
++ return 0;
++}
++
++static int
++ramses_pcmcia_configure_socket(unsigned int sock, socket_state_t *state)
++{
++ /* The Ramses uses the Maxim MAX1602, with the following connections:
++ *
++ * Socket 0 (PCMCIA):
++ * MAX1602 PXA_IDP Register
++ * Pin Signal RAMSES_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 RAMSES_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)
++ *
++ */
++
++ if (sock == 1) {
++
++ switch (state->Vcc) {
++ case 0:
++ RAMSES_CPLD_PCCARD_EN |= PCC1_ENABLE; // disable socket
++ udelay(200);
++ RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3);
++ break;
++
++ case 33:
++ RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3);
++ RAMSES_CPLD_PCCARD_PWR |= PCC1_PWR3;
++ RAMSES_CPLD_PCCARD_EN &= ~PCC1_ENABLE; //turn it on
++ break;
++
++ case 50:
++ RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3);
++ RAMSES_CPLD_PCCARD_PWR |= PCC1_PWR2;
++ RAMSES_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:
++ RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1);
++ break;
++
++ case 120:
++ RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1);
++ RAMSES_CPLD_PCCARD_PWR |= PCC1_PWR1;
++ break;
++
++ default:
++ if (state->Vpp == state->Vcc)
++ RAMSES_CPLD_PCCARD_PWR =
++ (RAMSES_CPLD_PCCARD_PWR &
++ ~(PCC1_PWR0 | PCC1_PWR1)) | PCC1_PWR0;
++ else {
++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
++ __FUNCTION__, state->Vpp);
++ return -1;
++ }
++ }
++ RAMSES_CPLD_PCCARD_EN = (state->flags & SS_RESET) ? (RAMSES_CPLD_PCCARD_EN | PCC1_RESET)
++ : (RAMSES_CPLD_PCCARD_EN & ~PCC1_RESET);
++ }
++ return 0;
++}
++
++struct pcmcia_low_level ramses_pcmcia_ops = {
++ ramses_pcmcia_init,
++ ramses_pcmcia_shutdown,
++ ramses_pcmcia_socket_state,
++ ramses_pcmcia_get_irq_info,
++ ramses_pcmcia_configure_socket
++};
+--- linux-2.4.21/drivers/scsi/scsi.h~usb-sonycamera
++++ linux-2.4.21/drivers/scsi/scsi.h
+@@ -610,6 +610,7 @@
+ unsigned remap:1; /* support remapping */
+ unsigned starved:1; /* unable to process commands because
+ host busy */
++ unsigned no_start_on_add:1; /* do not issue start on add */
+
+ // Flag to allow revalidate to succeed in sd_open
+ int allow_revalidate;
+--- linux-2.4.21/drivers/scsi/scsi_scan.c~usb-sonycamera
++++ linux-2.4.21/drivers/scsi/scsi_scan.c
+@@ -37,6 +37,8 @@
+ #define BLIST_ISDISK 0x100 /* Treat as (removable) disk */
+ #define BLIST_ISROM 0x200 /* Treat as (removable) CD-ROM */
+ #define BLIST_LARGELUN 0x400 /* LUNs larger than 7 despite reporting as SCSI 2 */
++#define BLIST_NOSTARTONADD 0x1000 /* do not do automatic start on add */
++
+
+ static void print_inquiry(unsigned char *data);
+ static int scan_scsis_single(unsigned int channel, unsigned int dev,
+@@ -110,9 +112,10 @@
+ {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */
+ {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */
+ {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */
+- {"HP", "A6188A", "*", BLIST_SPARSELUN}, /* HP Va7100 Array */
+- {"HP", "A6189A", "*", BLIST_SPARSELUN}, /* HP Va7400 Array */
+- {"HP", "A6189B", "*", BLIST_SPARSELUN}, /* HP Va7410 Array */
++ {"HP", "A6188A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7100 Array */
++ {"HP", "A6189A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7400 Array */
++ {"HP", "A6189B", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7110 Array */
++ {"HP", "A6218A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7410 Array */
+ {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
+ {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0
+ * extra reset */
+@@ -145,7 +148,7 @@
+ {"EMULEX", "MD21/S2 ESDI", "*", BLIST_SINGLELUN},
+ {"CANON", "IPUBJD", "*", BLIST_SPARSELUN},
+ {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
+- {"DEC","HSG80","*", BLIST_FORCELUN},
++ {"DEC","HSG80","*", BLIST_FORCELUN | BLIST_NOSTARTONADD},
+ {"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN},
+ {"COMPAQ","CR3500","*", BLIST_FORCELUN},
+ {"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+@@ -173,7 +176,11 @@
+ {"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
+ {"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN},
+ {"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN},
+- {"COMPAQ", "MSA1000", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"APPLE", "Xserve", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"COMPAQ", "MSA1000", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD},
++ {"COMPAQ", "MSA1000 VOLUME", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD},
++ {"COMPAQ", "HSV110", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD},
++ {"HP", "HSV100", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD},
+ {"HP", "C1557A", "*", BLIST_FORCELUN},
+ {"IBM", "AuSaV1S2", "*", BLIST_FORCELUN},
+ {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+@@ -182,7 +189,8 @@
+ {"HITACHI", "DF500", "*", BLIST_SPARSELUN},
+ {"HITACHI", "DF600", "*", BLIST_SPARSELUN},
+ {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+- {"HITACHI", "OPEN-", "*", BLIST_SPARSELUN}, /* HITACHI XP Arrays */
++ {"HITACHI", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HITACHI XP Arrays */
++ {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HITACHI 9960 */
+ {"WINSYS","FLASHDISK G6", "*", BLIST_SPARSELUN},
+ {"DotHill","SANnet RAID X300", "*", BLIST_SPARSELUN},
+ {"SUN", "T300", "*", BLIST_SPARSELUN},
+@@ -194,6 +202,12 @@
+ {"SGI", "TP9400", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"SGI", "TP9500", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"PLATYPUS", "CX5", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"Raidtec", "FCR", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"HP", "C7200", "*", BLIST_SPARSELUN}, /* Medium Changer */
++ {"SMSC", "USB 2 HS", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
++ {"NEC", "iStorage", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
+
+ /*
+ * Must be at end of list...
+@@ -209,10 +223,14 @@
+ static unsigned int max_scsi_luns = 1;
+ #endif
+
++static unsigned int scsi_allow_ghost_devices = 0;
++
+ #ifdef MODULE
+
+ MODULE_PARM(max_scsi_luns, "i");
+ MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)");
++MODULE_PARM(scsi_allow_ghost_devices, "i");
++MODULE_PARM_DESC(scsi_allow_ghost_devices, "allow devices marked as being offline to be accessed anyway (0 = off, else allow ghosts on lun 0 through scsi_allow_ghost_devices - 1");
+
+ #else
+
+@@ -232,6 +250,21 @@
+
+ __setup("max_scsi_luns=", scsi_luns_setup);
+
++static int __init scsi_allow_ghost_devices_setup(char *str)
++{
++ unsigned int tmp;
++
++ if (get_option(&str, &tmp) == 1) {
++ scsi_allow_ghost_devices = tmp;
++ return 1;
++ } else {
++ printk("scsi_allow_ghost_devices_setup: usage scsi_allow_ghost_devices=n (0: off else\nallow ghost devices (ghost devices are devices that report themselves as\nbeing offline but which we allow access to anyway) on lun 0 through n - 1.\n");
++ return 0;
++ }
++}
++
++__setup("scsi_allow_ghost_devices=", scsi_allow_ghost_devices_setup);
++
+ #endif
+
+ static void print_inquiry(unsigned char *data)
+@@ -608,6 +641,7 @@
+ } else {
+ /* assume no peripheral if any other sort of error */
+ scsi_release_request(SRpnt);
++ scsi_release_commandblocks(SDpnt);
+ return 0;
+ }
+ }
+@@ -618,6 +652,24 @@
+ */
+
+ /*
++ * If we are offline and we are on a LUN != 0, then skip this entry.
++ * If we are on a BLIST_FORCELUN device this will stop the scan at
++ * the first offline LUN (typically the correct thing to do). If
++ * we are on a BLIST_SPARSELUN device then this won't stop the scan,
++ * but it will keep us from having false entries in our device
++ * array. DL
++ *
++ * NOTE: Need to test this to make sure it doesn't cause problems
++ * with tape autoloaders, multidisc CD changers, and external
++ * RAID chassis that might use sparse luns or multiluns... DL
++ */
++ if (lun != 0 && (scsi_result[0] >> 5) == 1) {
++ scsi_release_request(SRpnt);
++ scsi_release_commandblocks(SDpnt);
++ return 0;
++ }
++
++ /*
+ * Get any flags for this device.
+ */
+ bflags = get_device_flags (scsi_result);
+@@ -655,8 +707,11 @@
+
+ SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
+ /* Use the peripheral qualifier field to determine online/offline */
+- if (((scsi_result[0] >> 5) & 7) == 1) SDpnt->online = FALSE;
+- else SDpnt->online = TRUE;
++ if ((((scsi_result[0] >> 5) & 7) == 1) &&
++ (lun >= scsi_allow_ghost_devices))
++ SDpnt->online = FALSE;
++ else
++ SDpnt->online = TRUE;
+ SDpnt->lockable = SDpnt->removable;
+ SDpnt->changed = 0;
+ SDpnt->access_count = 0;
+@@ -742,6 +797,13 @@
+ if ((bflags & BLIST_BORKEN) == 0)
+ SDpnt->borken = 0;
+
++ /*
++ * Some devices may not want to have a start command automatically
++ * issued when a device is added.
++ */
++ if (bflags & BLIST_NOSTARTONADD)
++ SDpnt->no_start_on_add = 1;
++
+ /*
+ * If we want to only allow I/O to one of the luns attached to this device
+ * at a time, then we set this flag.
+@@ -857,11 +919,26 @@
+ * I think we need REPORT LUNS in future to avoid scanning
+ * of unused LUNs. But, that is another item.
+ */
++ /*
+ if (*max_dev_lun < shpnt->max_lun)
+ *max_dev_lun = shpnt->max_lun;
+ else if ((max_scsi_luns >> 1) >= *max_dev_lun)
+ *max_dev_lun += shpnt->max_lun;
+ else *max_dev_lun = max_scsi_luns;
++ */
++ /*
++ * Blech...the above code is broken. When you have a device
++ * that is present, and it is a FORCELUN device, then we
++ * need to scan *all* the luns on that device. Besides,
++ * skipping the scanning of LUNs is a false optimization.
++ * Scanning for a LUN on a present device is a very fast
++ * operation, it's scanning for devices that don't exist that
++ * is expensive and slow (although if you are truly scanning
++ * through MAX_SCSI_LUNS devices that would be bad, I hope
++ * all of the controllers out there set a reasonable value
++ * in shpnt->max_lun). DL
++ */
++ *max_dev_lun = shpnt->max_lun;
+ return 1;
+ }
+ /*
+--- linux-2.4.21/drivers/scsi/sd.c~usb-sonycamera
++++ linux-2.4.21/drivers/scsi/sd.c
+@@ -775,7 +775,8 @@
+ char nbuff[6];
+ unsigned char *buffer;
+ unsigned long spintime_value = 0;
+- int the_result, retries, spintime;
++ int retries, spintime;
++ unsigned int the_result;
+ int sector_size;
+ Scsi_Request *SRpnt;
+
+@@ -817,7 +818,7 @@
+ do {
+ retries = 0;
+
+- while (retries < 3) {
++ do {
+ cmd[0] = TEST_UNIT_READY;
+ cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+ ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
+@@ -832,10 +833,10 @@
+
+ the_result = SRpnt->sr_result;
+ retries++;
+- if (the_result == 0
+- || SRpnt->sr_sense_buffer[2] != UNIT_ATTENTION)
+- break;
+- }
++ } while (retries < 3
++ && (the_result !=0
++ || ((driver_byte(the_result) & DRIVER_SENSE)
++ && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION)));
+
+ /*
+ * If the drive has indicated to us that it doesn't have
+@@ -853,24 +854,47 @@
+ break;
+ }
+
++ if ((driver_byte(the_result) & DRIVER_SENSE) == 0) {
++ /* no sense, TUR either succeeded or failed
++ * with a status error */
++ if(!spintime && the_result != 0)
++ printk(KERN_NOTICE "%s: Unit Not Ready, error = 0x%x\n", nbuff, the_result);
++ break;
++ }
++
++ /*
++ * The device does not want the automatic start to be issued.
++ */
++ if (rscsi_disks[i].device->no_start_on_add) {
++ break;
++ }
++
++ /*
++ * If manual intervention is required, or this is an
++ * absent USB storage device, a spinup is meaningless.
++ */
++ if (SRpnt->sr_sense_buffer[2] == NOT_READY &&
++ SRpnt->sr_sense_buffer[12] == 4 /* not ready */ &&
++ SRpnt->sr_sense_buffer[13] == 3) {
++ break; /* manual intervention required */
+ /* Look for non-removable devices that return NOT_READY.
+ * Issue command to spin up drive for these cases. */
+- if (the_result && !rscsi_disks[i].device->removable &&
+- SRpnt->sr_sense_buffer[2] == NOT_READY) {
++ } else if (the_result && !rscsi_disks[i].device->removable &&
++ SRpnt->sr_sense_buffer[2] == NOT_READY) {
+ unsigned long time1;
+ if (!spintime) {
+ printk("%s: Spinning up disk...", nbuff);
+ cmd[0] = START_STOP;
+ cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
+- ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
+- cmd[1] |= 1; /* Return immediately */
++ ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
++ cmd[1] |= 1; /* Return immediately */
+ memset((void *) &cmd[2], 0, 8);
+- cmd[4] = 1; /* Start spin cycle */
++ cmd[4] = 1; /* Start spin cycle */
+ SRpnt->sr_cmd_len = 0;
+ SRpnt->sr_sense_buffer[0] = 0;
+ SRpnt->sr_sense_buffer[2] = 0;
+
+- SRpnt->sr_data_direction = SCSI_DATA_READ;
++ SRpnt->sr_data_direction = SCSI_DATA_NONE;
+ scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
+ 0/*512*/, SD_TIMEOUT, MAX_RETRIES);
+ spintime_value = jiffies;
+@@ -883,6 +907,14 @@
+ time1 = schedule_timeout(time1);
+ } while(time1);
+ printk(".");
++ } else {
++ /* we don't understand the sense code, so it's
++ * probably pointless to loop */
++ if(!spintime) {
++ printk(KERN_NOTICE "%s: Unit Not Ready, sense:\n", nbuff);
++ print_req_sense("", SRpnt);
++ }
++ break;
+ }
+ } while (the_result && spintime &&
+ time_after(spintime_value + 100 * HZ, jiffies));
+--- linux-2.4.21/drivers/sound/ac97_codec.c~ucb1x00
++++ linux-2.4.21/drivers/sound/ac97_codec.c
+@@ -547,6 +547,12 @@
+ val = SOUND_CAP_EXCL_INPUT;
+ break;
+
++ case SOUND_MIXER_AC97:
++ if (get_user(val, (int *)arg))
++ return -EFAULT;
++ val = codec->codec_read(codec, val);
++ return put_user(val, (int *)arg);
++
+ default: /* read a specific mixer */
+ i = _IOC_NR(cmd);
+
+@@ -575,6 +581,11 @@
+ codec->recmask_io(codec, 0, val);
+
+ return 0;
++
++ case SOUND_MIXER_AC97:
++ codec->codec_write(codec, val >> 16 & 0xffff, val & 0xffff);
++ return 0;
++
+ default: /* write a specific mixer */
+ i = _IOC_NR(cmd);
+
+--- linux-2.4.21/drivers/sound/pxa-ac97.c~pxa-ac97
++++ linux-2.4.21/drivers/sound/pxa-ac97.c
+@@ -27,6 +27,7 @@
+ #include <linux/sound.h>
+ #include <linux/soundcard.h>
+ #include <linux/ac97_codec.h>
++#include <linux/pm.h>
+
+ #include <asm/hardware.h>
+ #include <asm/irq.h>
+@@ -164,6 +165,11 @@
+ //pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x1ff7);
+ pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x0050);
+ pxa_ac97_write(&pxa_ac97_codec, 0x6c, 0x0030);
++#if CONFIG_ARCH_RAMSES
++ pxa_ac97_codec.supported_mixers = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN;
++ pxa_ac97_codec.stereo_mixers = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN;
++ pxa_ac97_codec.record_sources = SOUND_MASK_MIC | SOUND_MASK_LINE;
++#endif
+ }
+
+ pxa_ac97_refcount++;
+@@ -198,7 +204,7 @@
+ static int mixer_ioctl( struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+ {
+- int ret, val;
++ int ret;
+
+ ret = pxa_ac97_codec.mixer_ioctl(&pxa_ac97_codec, cmd, arg);
+ if (ret)
+@@ -282,6 +288,7 @@
+ /* fall through */
+
+ case SOUND_PCM_READ_RATE:
++ val = 0;
+ if (file->f_mode & FMODE_READ)
+ val = codec_adc_rate;
+ if (file->f_mode & FMODE_WRITE)
+@@ -342,6 +349,44 @@
+ };
+
+
++#ifdef CONFIG_PM
++
++static int pxa_ac97_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
++{
++ down(&pxa_ac97_mutex);
++
++ switch (rqst) {
++ case PM_SUSPEND:
++ // TODO: set to low-power state?
++ GCR = GCR_ACLINK_OFF;
++ CKEN &= ~CKEN2_AC97;
++ break;
++
++ case PM_RESUME:
++ CKEN |= CKEN2_AC97;
++
++ GCR = 0;
++ udelay(10);
++ GCR = GCR_COLD_RST|GCR_CDONE_IE|GCR_SDONE_IE;
++ while (!(GSR & GSR_PCR)) {
++ schedule();
++ }
++
++ // 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, 0x0050);
++ pxa_ac97_write(&pxa_ac97_codec, 0x6c, 0x0030);
++ break;
++ }
++
++ up(&pxa_ac97_mutex);
++
++ return 0;
++}
++
++#endif
++
++
+ static int __init pxa_ac97_init(void)
+ {
+ int ret;
+@@ -354,11 +399,18 @@
+ ac97_audio_state.dev_dsp = register_sound_dsp(&ac97_audio_fops, -1);
+ pxa_ac97_codec.dev_mixer = register_sound_mixer(&mixer_fops, -1);
+
++#ifdef PM_DEBUG
++ ac97_audio_state.pmdev = pm_register(PM_SYS_UNKNOWN, 0x71783937, pxa_ac97_pm_callback, "pxa-ac97");
++#else
++ ac97_audio_state.pmdev = pm_register(PM_SYS_UNKNOWN, 0x71783937, pxa_ac97_pm_callback);
++#endif
++
+ return 0;
+ }
+
+ static void __exit pxa_ac97_exit(void)
+ {
++ pm_unregister(ac97_audio_state.pmdev);
+ unregister_sound_dsp(ac97_audio_state.dev_dsp);
+ unregister_sound_mixer(pxa_ac97_codec.dev_mixer);
+ pxa_ac97_put();
+--- linux-2.4.21/drivers/sound/pxa-audio.h~pm
++++ linux-2.4.21/drivers/sound/pxa-audio.h
+@@ -47,6 +47,9 @@
+ 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 */
++#ifdef CONFIG_PM
++ struct pm_dev *pmdev; /* Power management */
++#endif
+ } audio_state_t;
+
+ extern int pxa_audio_attach(struct inode *inode, struct file *file,
+--- linux-2.4.21/drivers/usb/Config.in~pxa-usb
++++ linux-2.4.21/drivers/usb/Config.in
+@@ -5,7 +5,7 @@
+ comment 'USB support'
+
+ # 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
++if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SA1111" = "y" -o "$CONFIG_ARCH_AT91RM9200" = "y" -o "$CONFIG_ARCH_PXA" = "y" ]; then
+ tristate 'Support for USB' CONFIG_USB
+ else
+ define_bool CONFIG_USB n
+--- linux-2.4.21/drivers/usb/Makefile~usb-sl811
++++ linux-2.4.21/drivers/usb/Makefile
+@@ -80,6 +80,9 @@
+ ifeq ($(CONFIG_USB_OHCI),y)
+ obj-y += host/usb-ohci.o host/usb-ohci-sa1111.o
+ endif
++
++subdir-$(CONFIG_USB_SL811HS_ALT)+= host
++
+ subdir-$(CONFIG_USB_OHCI_AT91) += host
+ ifeq ($(CONFIG_USB_OHCI_AT91),y)
+ obj-y += host/usb-ohci.o
+--- linux-2.4.21/drivers/usb/hcd.c~ramses-usb
++++ linux-2.4.21/drivers/usb/hcd.c
+@@ -662,7 +662,9 @@
+ pci_set_drvdata(dev, hcd);
+ hcd->driver = driver;
+ hcd->description = driver->description;
++#ifdef TODO
+ hcd->pdev = dev;
++#endif
+ printk (KERN_INFO "%s %s: %s\n",
+ hcd->description, dev->slot_name, dev->name);
+
+@@ -1201,6 +1203,7 @@
+ return status;
+
+ // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag
++#ifdef TODO
+ if (usb_pipecontrol (urb->pipe))
+ urb->setup_dma = pci_map_single (
+ #ifdef CONFIG_PCI
+@@ -1223,7 +1226,7 @@
+ usb_pipein (urb->pipe)
+ ? PCI_DMA_FROMDEVICE
+ : PCI_DMA_TODEVICE);
+-
++#endif
+ if (urb->dev == hcd->bus->root_hub)
+ status = rh_urb_enqueue (hcd, urb);
+ else
+@@ -1488,6 +1491,7 @@
+ // hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
+
+ // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag
++#ifdef TODO
+ if (usb_pipecontrol (urb->pipe))
+ pci_unmap_single (
+ #ifdef CONFIG_PCI
+@@ -1510,6 +1514,7 @@
+ usb_pipein (urb->pipe)
+ ? PCI_DMA_FROMDEVICE
+ : PCI_DMA_TODEVICE);
++#endif
+
+ /* pass ownership to the completion handler */
+ urb->complete (urb);
+--- linux-2.4.21/drivers/usb/host/Config.in~usb-sl811
++++ linux-2.4.21/drivers/usb/host/Config.in
+@@ -13,6 +13,9 @@
+ 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" ]; then
++ dep_tristate ' SL811HS Alternate (x86, StrongARM, isosynchronous mode)' CONFIG_USB_SL811HS_ALT $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.21/drivers/usb/host/Makefile~usb-sl811
++++ linux-2.4.21/drivers/usb/host/Makefile
+@@ -10,6 +10,7 @@
+ obj-$(CONFIG_USB_UHCI) += usb-uhci.o
+ obj-$(CONFIG_USB_OHCI) += usb-ohci.o usb-ohci-pci.o
+ obj-$(CONFIG_USB_OHCI_SA1111) += usb-ohci.o usb-ohci-sa1111.o
++obj-$(CONFIG_USB_SL811HS_ALT) += sl811.o
+ obj-$(CONFIG_USB_OHCI_AT91) += usb-ohci.o
+
+ # Extract lists of the multi-part drivers.
+--- /dev/null
++++ linux-2.4.21/drivers/usb/host/sl811.c
+@@ -0,0 +1,2782 @@
++/*
++ * SL811 Host Controller Interface driver for USB.
++ *
++ * Copyright (c) 2003/06, Courage Co., Ltd.
++ *
++ * Based on:
++ * 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
++ * Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
++ * Adam Richter, Gregory P. Smith;
++ * 2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
++ * 3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
++ *
++ * It's now support isochornous mode and more effective than hc_sl811.o
++ * Support x86 architecture now.
++ *
++ * 19.09.2003 (05.06.2003) HNE
++ * sl811_alloc_hc: Set "bus->bus_name" at init.
++ * sl811_reg_test (hc_reset,regTest):
++ * Stop output at first failed pattern.
++ * Down-Grade for Kernel 2.4.20 and from 2.4.22
++ * Split hardware dependency into files sl811-x86.h and sl811-arm.h.
++ *
++ * 22.09.2003 HNE
++ * sl811_found_hc: First patterntest, than interrupt enable.
++ * Do nothing, if patterntest failed. Release IO if failed.
++ * Stop Interrupts first, than remove handle. (Old blocked Shared IRQ)
++ * Alternate IO-Base for second Controller (CF/USB1).
++ *
++ * 24.09.2003 HNE
++ * Remove all arm specific source (moved into include/asm/sl811-hw.h).
++ *
++ * 03.10.2003 HNE
++ * Low level only for port IO into hardware-include.
++ *
++ * To do:
++ * 1.Modify the timeout part, it's some messy
++ * 2.Use usb-a and usb-b set in Ping-Pong mode
++ * o Floppy do not work.
++ * o driver crash, if io region can't register
++ * o Only tested as module. Compiled-in version not tested!
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the 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/kernel.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/smp_lock.h>
++#include <linux/list.h>
++#include <linux/ioport.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <linux/usb.h>
++
++#include "../hcd.h"
++#include "../hub.h"
++#include "sl811.h"
++
++#define DRIVER_VERSION "v0.30"
++#define MODNAME "SL811"
++#define DRIVER_AUTHOR "Yin Aihua <yinah@couragetech.com.cn>, Henry Nestler <hne@ist1.de>"
++#define DRIVER_DESC "Sl811 USB Host Controller Alternate Driver"
++
++static LIST_HEAD(sl811_hcd_list);
++
++/*
++ * 0: normal prompt and information
++ * 1: error should not occur in normal
++ * 2: error maybe occur in normal
++ * 3: useful and detail debug information
++ * 4: function level enter and level inforamtion
++ * 5: endless information will output because of timer function or interrupt
++ */
++static int debug = 0;
++MODULE_PARM(debug,"i");
++MODULE_PARM_DESC(debug,"debug level");
++
++#include <asm/sl811-hw.h> /* Include hardware and board depens */
++
++static void sl811_rh_int_timer_do(unsigned long ptr);
++static void sl811_transfer_done(struct sl811_hc *hc, int sof);
++
++/*
++ * Read a byte of data from the SL811H/SL11H
++ */
++static __u8 inline sl811_read(struct sl811_hc *hc, __u8 offset)
++{
++ sl811_write_index (hc, offset);
++ return (sl811_read_data (hc));
++}
++
++/*
++ * Write a byte of data to the SL811H/SL11H
++ */
++static void inline sl811_write(struct sl811_hc *hc, __u8 offset, __u8 data)
++{
++ sl811_write_index_data (hc, offset, data);
++}
++
++/*
++ * Read consecutive bytes of data from the SL811H/SL11H buffer
++ */
++static void inline sl811_read_buf(struct sl811_hc *hc, __u8 offset, __u8 *buf, __u8 size)
++{
++ sl811_write_index (hc, offset);
++ while (size--) {
++ *buf++ = sl811_read_data(hc);
++ }
++}
++
++/*
++ * Write consecutive bytes of data to the SL811H/SL11H buffer
++ */
++static void inline sl811_write_buf(struct sl811_hc *hc, __u8 offset, __u8 *buf, __u8 size)
++{
++ sl811_write_index (hc, offset);
++ while (size--) {
++ sl811_write_data (hc, *buf);
++ buf++;
++ }
++}
++
++/*
++ * This routine test the Read/Write functionality of SL811HS registers
++ */
++static int sl811_reg_test(struct sl811_hc *hc)
++{
++ int i, data, result = 0;
++ __u8 buf[256];
++
++ for (i = 0x10; i < 256; i++) {
++ /* save the original buffer */
++ buf[i] = sl811_read(hc, i);
++
++ /* Write the new data to the buffer */
++ sl811_write(hc, i, ~i);
++ }
++
++ /* compare the written data */
++ for (i = 0x10; i < 256; i++) {
++ data = sl811_read(hc, i);
++ if (data != (__u8) ~i) {
++ PDEBUG(1, "reg %02x expected %02x got %02x", i, (__u8) ~i, data);
++ result = -1;
++
++ /* If no Debug, show only first failed Address */
++ if (!debug)
++ break;
++ }
++ }
++
++ /* restore the data */
++ for (i = 0x10; i < 256; i++)
++ sl811_write(hc, i, buf[i]);
++
++ return result;
++}
++
++/*
++ * Display all SL811HS register values
++ */
++#if 0 /* unused (hne) */
++static void sl811_reg_show(struct sl811_hc *hc)
++{
++ int i;
++
++ for (i = 0; i < 256; i++)
++ PDEBUG(4, "offset %d: 0x%x", i, sl811_read(hc, i));
++}
++#endif
++
++/*
++ * This function enables SL811HS interrupts
++ */
++static void sl811_enable_interrupt(struct sl811_hc *hc)
++{
++ PDEBUG(4, "enter");
++ sl811_write(hc, SL811_INTR, SL811_INTR_DONE_A | SL811_INTR_SOF | SL811_INTR_INSRMV);
++}
++
++/*
++ * This function disables SL811HS interrupts
++ */
++static void sl811_disable_interrupt(struct sl811_hc *hc)
++{
++ PDEBUG(4, "enter");
++ // Disable all other interrupt except for insert/remove.
++ sl811_write(hc, SL811_INTR, SL811_INTR_INSRMV);
++}
++
++/*
++ * SL811 Virtual Root Hub
++ */
++
++/* Device descriptor */
++static __u8 sl811_rh_dev_des[] =
++{
++ 0x12, /* __u8 bLength; */
++ 0x01, /* __u8 bDescriptorType; Device */
++ 0x10, /* __u16 bcdUSB; v1.1 */
++ 0x01,
++ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
++ 0x00, /* __u8 bDeviceSubClass; */
++ 0x00, /* __u8 bDeviceProtocol; */
++ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
++ 0x00, /* __u16 idVendor; */
++ 0x00,
++ 0x00, /* __u16 idProduct; */
++ 0x00,
++ 0x00, /* __u16 bcdDevice; */
++ 0x00,
++ 0x00, /* __u8 iManufacturer; */
++ 0x02, /* __u8 iProduct; */
++ 0x01, /* __u8 iSerialNumber; */
++ 0x01 /* __u8 bNumConfigurations; */
++};
++
++/* Configuration descriptor */
++static __u8 sl811_rh_config_des[] =
++{
++ 0x09, /* __u8 bLength; */
++ 0x02, /* __u8 bDescriptorType; Configuration */
++ 0x19, /* __u16 wTotalLength; */
++ 0x00,
++ 0x01, /* __u8 bNumInterfaces; */
++ 0x01, /* __u8 bConfigurationValue; */
++ 0x00, /* __u8 iConfiguration; */
++ 0x40, /* __u8 bmAttributes;
++ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup,
++ 4..0: resvd */
++ 0x00, /* __u8 MaxPower; */
++
++ /* interface */
++ 0x09, /* __u8 if_bLength; */
++ 0x04, /* __u8 if_bDescriptorType; Interface */
++ 0x00, /* __u8 if_bInterfaceNumber; */
++ 0x00, /* __u8 if_bAlternateSetting; */
++ 0x01, /* __u8 if_bNumEndpoints; */
++ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
++ 0x00, /* __u8 if_bInterfaceSubClass; */
++ 0x00, /* __u8 if_bInterfaceProtocol; */
++ 0x00, /* __u8 if_iInterface; */
++
++ /* endpoint */
++ 0x07, /* __u8 ep_bLength; */
++ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
++ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
++ 0x03, /* __u8 ep_bmAttributes; Interrupt */
++ 0x08, /* __u16 ep_wMaxPacketSize; */
++ 0x00,
++ 0xff /* __u8 ep_bInterval; 255 ms */
++};
++
++/* root hub class descriptor*/
++static __u8 sl811_rh_hub_des[] =
++{
++ 0x09, /* __u8 bLength; */
++ 0x29, /* __u8 bDescriptorType; Hub-descriptor */
++ 0x01, /* __u8 bNbrPorts; */
++ 0x00, /* __u16 wHubCharacteristics; */
++ 0x00,
++ 0x50, /* __u8 bPwrOn2pwrGood; 2ms */
++ 0x00, /* __u8 bHubContrCurrent; 0 mA */
++ 0xfc, /* __u8 DeviceRemovable; *** 7 Ports max *** */
++ 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
++};
++
++/*
++ * This function examine the port change in the virtual root hub. HUB INTERRUPT ENDPOINT.
++ */
++static int sl811_rh_send_irq(struct sl811_hc *hc, __u8 *rh_change, int rh_len)
++{
++ __u8 data = 0;
++
++ PDEBUG(5, "enter");
++
++ /*
++ * Right now, It is assume the power is good and no changes and only one port.
++ */
++ if (hc->rh_status.wPortChange & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) {
++ data = 1<<1;
++ *(__u8 *)rh_change = data;
++ return 1;
++ } else
++ return 0;
++}
++
++/*
++ * This function creates a timer that act as interrupt pipe in the virtual hub.
++ *
++ * Note: The virtual root hub's interrupt pipe are polled by the timer
++ * every "interval" ms
++ */
++static void sl811_rh_init_int_timer(struct urb * urb)
++{
++ struct sl811_hc *hc = urb->dev->bus->hcpriv;
++ hc->rh.interval = urb->interval;
++
++ init_timer(&hc->rh.rh_int_timer);
++ hc->rh.rh_int_timer.function = sl811_rh_int_timer_do;
++ hc->rh.rh_int_timer.data = (unsigned long)urb;
++ hc->rh.rh_int_timer.expires = jiffies +
++ (HZ * (urb->interval < 30? 30: urb->interval)) / 1000;
++ add_timer (&hc->rh.rh_int_timer);
++}
++
++/*
++ * This function is called when the timer expires. It gets the the port
++ * change data and pass along to the upper protocol.
++ */
++static void sl811_rh_int_timer_do(unsigned long ptr)
++{
++ int len;
++ struct urb *urb = (struct urb *)ptr;
++ struct sl811_hc *hc = urb->dev->bus->hcpriv;
++ PDEBUG (5, "enter");
++
++ if(hc->rh.send) {
++ len = sl811_rh_send_irq(hc, urb->transfer_buffer,
++ urb->transfer_buffer_length);
++ if (len > 0) {
++ urb->actual_length = len;
++ if (urb->complete)
++ urb->complete(urb);
++ }
++ }
++
++#ifdef SL811_TIMEOUT
++
++{
++ struct list_head *head, *tmp;
++ struct sl811_urb_priv *urbp;
++ struct urb *u;
++ int i;
++ static int timeout_count = 0;
++
++// check time out every second
++ if (++timeout_count > 4) {
++ int max_scan = hc->active_urbs;
++ timeout_count = 0;
++ for (i = 0; i < 6; ++i) {
++ head = &hc->urb_list[i];
++ tmp = head->next;
++ while (tmp != head && max_scan--) {
++ u = list_entry(tmp, struct urb, urb_list);
++ urbp = (struct sl811_urb_priv *)u->hcpriv;
++ tmp = tmp->next;
++ // Check if the URB timed out
++ if (u->timeout && time_after_eq(jiffies, urbp->inserttime + u->timeout)) {
++ PDEBUG(3, "urb = %p time out, we kill it", urb);
++ u->transfer_flags |= USB_TIMEOUT_KILLED;
++ }
++ }
++ }
++ }
++}
++
++#endif
++ // re-activate the timer
++ sl811_rh_init_int_timer(urb);
++}
++
++/* helper macro */
++#define OK(x) len = (x); break
++
++/*
++ * This function handles all USB request to the the virtual root hub
++ */
++static int sl811_rh_submit_urb(struct urb *urb)
++{
++ struct usb_device *usb_dev = urb->dev;
++ struct sl811_hc *hc = usb_dev->bus->hcpriv;
++ struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet;
++ void *data = urb->transfer_buffer;
++ int buf_len = urb->transfer_buffer_length;
++ unsigned int pipe = urb->pipe;
++ __u8 data_buf[16];
++ __u8 *bufp = data_buf;
++ int len = 0;
++ int status = 0;
++
++ __u16 bmRType_bReq;
++ __u16 wValue;
++ __u16 wIndex;
++ __u16 wLength;
++
++ if (usb_pipeint(pipe)) {
++ hc->rh.urb = urb;
++ hc->rh.send = 1;
++ hc->rh.interval = urb->interval;
++ sl811_rh_init_int_timer(urb);
++ urb->status = 0;
++
++ return 0;
++ }
++
++ bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
++ wValue = le16_to_cpu (cmd->wValue);
++ wIndex = le16_to_cpu (cmd->wIndex);
++ wLength = le16_to_cpu (cmd->wLength);
++
++ PDEBUG(5, "submit rh urb, req = %d(%x) len=%d", bmRType_bReq, bmRType_bReq, wLength);
++
++ /* Request Destination:
++ without flags: Device,
++ USB_RECIP_INTERFACE: interface,
++ USB_RECIP_ENDPOINT: endpoint,
++ USB_TYPE_CLASS means HUB here,
++ USB_RECIP_OTHER | USB_TYPE_CLASS almost ever means HUB_PORT here
++ */
++ switch (bmRType_bReq) {
++ case RH_GET_STATUS:
++ *(__u16 *)bufp = cpu_to_le16(1);
++ OK(2);
++
++ case RH_GET_STATUS | USB_RECIP_INTERFACE:
++ *(__u16 *)bufp = cpu_to_le16(0);
++ OK(2);
++
++ case RH_GET_STATUS | USB_RECIP_ENDPOINT:
++ *(__u16 *)bufp = cpu_to_le16(0);
++ OK(2);
++
++ case RH_GET_STATUS | USB_TYPE_CLASS:
++ *(__u32 *)bufp = cpu_to_le32(0);
++ OK(4);
++
++ case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS:
++ *(__u32 *)bufp = cpu_to_le32(hc->rh_status.wPortChange<<16 | hc->rh_status.wPortStatus);
++ OK(4);
++
++ case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT:
++ switch (wValue) {
++ case 1:
++ OK(0);
++ }
++ break;
++
++ case RH_CLEAR_FEATURE | USB_TYPE_CLASS:
++ switch (wValue) {
++ case C_HUB_LOCAL_POWER:
++ OK(0);
++
++ case C_HUB_OVER_CURRENT:
++ OK(0);
++ }
++ break;
++
++ case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
++ switch (wValue) {
++ case USB_PORT_FEAT_ENABLE:
++ hc->rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE;
++ OK(0);
++
++ case USB_PORT_FEAT_SUSPEND:
++ hc->rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND;
++ OK(0);
++
++ case USB_PORT_FEAT_POWER:
++ hc->rh_status.wPortStatus &= ~USB_PORT_STAT_POWER;
++ OK(0);
++
++ case USB_PORT_FEAT_C_CONNECTION:
++ hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
++ OK(0);
++
++ case USB_PORT_FEAT_C_ENABLE:
++ hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE;
++ OK(0);
++
++ case USB_PORT_FEAT_C_SUSPEND:
++ hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND;
++ OK(0);
++
++ case USB_PORT_FEAT_C_OVER_CURRENT:
++ hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT;
++ OK(0);
++
++ case USB_PORT_FEAT_C_RESET:
++ hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET;
++ OK(0);
++ }
++ break;
++
++ case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
++ switch (wValue) {
++ case USB_PORT_FEAT_SUSPEND:
++ hc->rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND;
++ OK(0);
++
++ case USB_PORT_FEAT_RESET:
++ hc->rh_status.wPortStatus |= USB_PORT_STAT_RESET;
++ hc->rh_status.wPortChange = 0;
++ hc->rh_status.wPortChange |= USB_PORT_STAT_C_RESET;
++ hc->rh_status.wPortStatus &= ~USB_PORT_STAT_RESET;
++ hc->rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
++ OK(0);
++
++ case USB_PORT_FEAT_POWER:
++ hc->rh_status.wPortStatus |= USB_PORT_STAT_POWER;
++ OK(0);
++
++ case USB_PORT_FEAT_ENABLE:
++ hc->rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
++ OK(0);
++ }
++ break;
++
++ case RH_SET_ADDRESS:
++ hc->rh.devnum = wValue;
++ OK(0);
++
++ case RH_GET_DESCRIPTOR:
++ switch ((wValue & 0xff00) >> 8) {
++ case USB_DT_DEVICE:
++ len = sizeof(sl811_rh_dev_des);
++ bufp = sl811_rh_dev_des;
++ OK(len);
++
++ case USB_DT_CONFIG:
++ len = sizeof(sl811_rh_config_des);
++ bufp = sl811_rh_config_des;
++ OK(len);
++
++ case USB_DT_STRING:
++ len = usb_root_hub_string(wValue & 0xff, (int)(long)0, "SL811HS", data, wLength);
++ if (len > 0) {
++ bufp = data;
++ OK(len);
++ }
++
++ default:
++ status = -EPIPE;
++ }
++ break;
++
++ case RH_GET_DESCRIPTOR | USB_TYPE_CLASS:
++ len = sizeof(sl811_rh_hub_des);
++ bufp = sl811_rh_hub_des;
++ OK(len);
++
++ case RH_GET_CONFIGURATION:
++ bufp[0] = 0x01;
++ OK(1);
++
++ case RH_SET_CONFIGURATION:
++ OK(0);
++
++ default:
++ PDEBUG(1, "unsupported root hub command");
++ status = -EPIPE;
++ }
++
++ len = min(len, buf_len);
++ if (data != bufp)
++ memcpy(data, bufp, len);
++ urb->actual_length = len;
++ urb->status = status;
++
++ PDEBUG(5, "len = %d, status = %d", len, status);
++
++ urb->hcpriv = NULL;
++ urb->dev = NULL;
++ if (urb->complete)
++ urb->complete(urb);
++
++ return 0;
++}
++
++/*
++ * This function unlinks the URB
++ */
++static int sl811_rh_unlink_urb(struct urb *urb)
++{
++ struct sl811_hc *hc = urb->dev->bus->hcpriv;
++
++ PDEBUG(5, "enter");
++
++ if (hc->rh.urb == urb) {
++ hc->rh.send = 0;
++ del_timer(&hc->rh.rh_int_timer);
++ hc->rh.urb = NULL;
++ urb->hcpriv = NULL;
++ usb_dec_dev_use(urb->dev);
++ urb->dev = NULL;
++ if (urb->transfer_flags & USB_ASYNC_UNLINK) {
++ urb->status = -ECONNRESET;
++ if (urb->complete)
++ urb->complete(urb);
++ } else
++ urb->status = -ENOENT;
++ }
++
++ return 0;
++}
++
++/*
++ * This function connect the virtual root hub to the USB stack
++ */
++static int sl811_connect_rh(struct sl811_hc * hc)
++{
++ struct usb_device *usb_dev;
++
++ hc->rh.devnum = 0;
++ usb_dev = usb_alloc_dev(NULL, hc->bus);
++ if (!usb_dev)
++ return -ENOMEM;
++
++ hc->bus->root_hub = usb_dev;
++ usb_connect(usb_dev);
++
++ if (usb_new_device(usb_dev)) {
++ usb_free_dev(usb_dev);
++ return -ENODEV;
++ }
++
++ PDEBUG(5, "leave success");
++
++ return 0;
++}
++
++/*
++ * This function allocates private data space for the usb device
++ */
++static int sl811_alloc_dev_priv(struct usb_device *usb_dev)
++{
++ return 0;
++}
++
++/*
++ * This function de-allocates private data space for the usb devic
++ */
++static int sl811_free_dev_priv (struct usb_device *usb_dev)
++{
++ return 0;
++}
++
++/*
++ * This function allocates private data space for the urb
++ */
++static struct sl811_urb_priv* sl811_alloc_urb_priv(struct urb *urb)
++{
++ struct sl811_urb_priv *urbp;
++
++ urbp = kmalloc(sizeof(*urbp), GFP_KERNEL);
++ if (!urbp)
++ return NULL;
++
++ memset(urbp, 0, sizeof(*urbp));
++
++ INIT_LIST_HEAD(&urbp->td_list);
++
++ urbp->urb = urb;
++ urb->hcpriv = urbp;
++
++ return urbp;
++}
++
++/*
++ * This function free private data space for the urb
++ */
++static void sl811_free_urb_priv(struct urb *urb)
++{
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td;
++ struct list_head *head, *tmp;
++
++ if (!urbp)
++ return ;
++
++ head = &urbp->td_list;
++ tmp = head->next;
++
++ while (tmp != head) {
++ td = list_entry(tmp, struct sl811_td, td_list);
++ tmp = tmp->next;
++ kfree(td);
++ }
++
++ kfree(urbp);
++ urb->hcpriv = NULL;
++
++ return ;
++}
++
++/*
++ * This function calculate the bus time need by this td.
++ * Fix me! Can this use usb_calc_bus_time()?
++ */
++static void sl811_calc_td_time(struct sl811_td *td)
++{
++#if 1
++ int time;
++ int len = td->len;
++ struct sl811_hc *hc = td->urb->dev->bus->hcpriv;
++
++ if (hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED)
++ time = 8*8*len + 1024;
++ else {
++ if (td->ctrl & SL811_USB_CTRL_PREAMBLE)
++ time = 8*8*len + 2048;
++ else
++ time = 8*len + 256;
++ }
++
++ time += 2*10 * len;
++
++ td->bustime = time;
++
++#else
++
++ unsigned long tmp;
++ int time;
++ int low_speed = usb_pipeslow(td->urb->pipe);
++ int input_dir = usb_pipein(td->urb->pipe);
++ int bytecount = td->len;
++ int isoc = usb_pipeisoc(td->urb->pipe);
++
++ if (low_speed) { /* no isoc. here */
++ if (input_dir) {
++ tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;
++ time = (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
++ } else {
++ tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;
++ time = (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
++ }
++ } else if (!isoc){ /* for full-speed: */
++ tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
++ time = (9107L + BW_HOST_DELAY + tmp);
++ } else { /* for isoc: */
++ tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
++ time = (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
++ }
++
++ td->bustime = time / 84;
++
++#endif
++}
++
++/*
++ * This function calculate the remainder bus time in current frame.
++ */
++static inline int sl811_calc_bus_remainder(struct sl811_hc *hc)
++{
++ return (sl811_read(hc, SL811_SOFCNTDIV) * 64);
++}
++
++/*
++ * This function allocates td for the urb
++ */
++static struct sl811_td* sl811_alloc_td(struct urb *urb)
++{
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td;
++
++ td = kmalloc(sizeof (*td), GFP_KERNEL);
++ if (!td)
++ return NULL;
++
++ memset(td, 0, sizeof(*td));
++
++ INIT_LIST_HEAD(&td->td_list);
++
++ td->urb = urb;
++ list_add_tail(&td->td_list, &urbp->td_list);
++
++ return td;
++}
++
++/*
++ * Fill the td.
++ */
++static inline void sl811_fill_td(struct sl811_td *td, __u8 ctrl, __u8 addr, __u8 len, __u8 pidep, __u8 dev, __u8 *buf)
++{
++ td->ctrl = ctrl;
++ td->addr = addr;
++ td->len = len;
++ td->pidep = pidep;
++ td->dev = dev;
++ td->buf = buf;
++ td->left = len;
++ td->errcnt = 3;
++}
++
++/*
++ * Fill the td.
++ */
++static inline void sl811_reset_td(struct sl811_td *td)
++{
++ td->status = 0;
++ td->left = td->len;
++ td->done = 0;
++ td->errcnt = 3;
++ td->nakcnt = 0;
++ td->td_status = 0;
++}
++
++static void sl811_print_td(int level, struct sl811_td *td)
++{
++ PDEBUG(level, "td = %p, ctrl = %x, addr = %x, len = %x, pidep = %x\n "
++ "dev = %x, status = %x, left = %x, errcnt = %x, done = %x\n "
++ "buf = %p, bustime = %d, td_status = %d\n",
++ td, td->ctrl, td->addr, td->len, td->pidep,
++ td->dev, td->status, td->left, td->errcnt, td->done,
++ td->buf, td->bustime, td->td_status);
++}
++
++/*
++ * Isochronous transfers
++ */
++static int sl811_submit_isochronous(struct urb *urb)
++{
++ __u8 dev = usb_pipedevice(urb->pipe);
++ __u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
++ __u8 ctrl = 0;
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td = NULL;
++ int i;
++
++ PDEBUG(4, "enter, urb = %p, urbp = %p", urb, urbp);
++
++ /* Can't have low speed bulk transfers */
++ if (usb_pipeslow(urb->pipe)) {
++ PDEBUG(1, "error, urb = %p, low speed device", urb);
++ return -EINVAL;
++ }
++
++ if (usb_pipeout(urb->pipe))
++ ctrl |= SL811_USB_CTRL_DIR_OUT;
++
++ ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE | SL811_USB_CTRL_ISO;
++
++ for (i = 0; i < urb->number_of_packets; i++) {
++ urb->iso_frame_desc[i].actual_length = 0;
++ urb->iso_frame_desc[i].status = -EXDEV;
++
++ td = sl811_alloc_td(urb);
++ if (!td)
++ return -ENOMEM;
++
++ sl811_fill_td(td, ctrl, SL811_DATA_START,
++ urb->iso_frame_desc[i].length,
++ pidep, dev,
++ urb->transfer_buffer + urb->iso_frame_desc[i].offset);
++ sl811_calc_td_time(td);
++ if (urbp->cur_td == NULL)
++ urbp->cur_td = urbp->first_td = td;
++ }
++
++ urbp->last_td = td;
++
++ PDEBUG(4, "leave success");
++
++/*
++// for debug
++ {
++ struct list_head *head, *tmp;
++ struct sl811_td *td;
++ int i = 0;
++ head = &urbp->td_list;
++ tmp = head->next;
++
++ if (list_empty(&urbp->td_list)) {
++ PDEBUG(1, "bug!!! td list is empty!");
++ return -ENODEV;
++ }
++
++ while (tmp != head) {
++ ++i;
++ td = list_entry(tmp, struct sl811_td, td_list);
++ PDEBUG(2, "td = %p, i = %d", td, i);
++ tmp = tmp->next;
++ }
++ }
++*/
++ return 0;
++}
++
++/*
++ * Reset isochronous transfers
++ */
++static void sl811_reset_isochronous(struct urb *urb)
++{
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td = NULL;
++ struct list_head *head, *tmp;
++ int i;
++
++ PDEBUG(4, "enter, urb = %p", urb);
++
++ for (i = 0; i < urb->number_of_packets; i++) {
++ urb->iso_frame_desc[i].actual_length = 0;
++ urb->iso_frame_desc[i].status = -EXDEV;
++ }
++
++ head = &urbp->td_list;
++ tmp = head->next;
++ while (tmp != head) {
++ td = list_entry(tmp, struct sl811_td, td_list);
++ tmp = tmp->next;
++ sl811_reset_td(td);
++ }
++
++ urbp->cur_td = urbp->first_td;
++
++ urb->status = -EINPROGRESS;
++ urb->actual_length = 0;
++ urb->error_count = 0;
++}
++
++/*
++ * Result the iso urb.
++ */
++static void sl811_result_isochronous(struct urb *urb)
++{
++ struct list_head *tmp, *head;
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ int status = 0;
++ struct sl811_td *td;
++ int i;
++
++ PDEBUG(4, "enter, urb = %p", urb);
++
++ urb->actual_length = 0;
++
++ i = 0;
++ head = &urbp->td_list;
++ tmp = head->next;
++ while (tmp != head) {
++ td = list_entry(tmp, struct sl811_td, td_list);
++ tmp = tmp->next;
++
++ if (!td->done) {
++ if (urbp->unlink)
++ urb->status = -ENOENT;
++ else {
++ PDEBUG(1, "we should not get here!");
++ urb->status = -EXDEV;
++ }
++ return ;
++ }
++ if (td->td_status) {
++ status = td->td_status;
++ urb->error_count++;
++ PDEBUG(1, "error: td = %p, td status = %d", td, td->td_status);
++ }
++
++ urb->iso_frame_desc[i].actual_length = td->len - td->left;
++ urb->actual_length += td->len - td->left;
++ urb->iso_frame_desc[i].status = td->td_status;
++ ++i;
++ if (td->left)
++ PDEBUG(3, "short packet, td = %p, len = %d, left = %d", td, td->len, td->left);
++ }
++
++ urb->status = status;
++/*
++// for debug
++ PDEBUG(2, "iso urb complete, len = %d, status =%d ", urb->actual_length, urb->status);
++*/
++ PDEBUG(4, "leave success");
++}
++
++/*
++ * Interrupt transfers
++ */
++static int sl811_submit_interrupt(struct urb *urb)
++{
++ int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
++ int len = urb->transfer_buffer_length;
++ __u8 *data = urb->transfer_buffer;
++ __u8 dev = usb_pipedevice(urb->pipe);
++ __u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
++ __u8 ctrl = 0;
++ struct sl811_hc *hc = urb->dev->bus->hcpriv;
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td = NULL;
++
++ PDEBUG(4, "enter, urb = %p", urb);
++
++ if (len > maxsze) {
++ PDEBUG(1, "length is big than max packet size, len = %d, max packet = %d", len, maxsze);
++ return -EINVAL;
++ }
++ if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED))
++ ctrl |= SL811_USB_CTRL_PREAMBLE;
++
++ ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
++ if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
++ ctrl |= SL811_USB_CTRL_TOGGLE_1;
++ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
++ td = sl811_alloc_td(urb);
++ if (!td)
++ return -ENOMEM;
++
++ sl811_fill_td(td, ctrl, SL811_DATA_START, len, pidep, dev, data);
++ sl811_calc_td_time(td);
++ urbp->cur_td = urbp->first_td = urbp->last_td = td;
++ urbp->interval = 0;
++
++ PDEBUG(4, "leave success");
++
++ return 0;
++}
++
++/*
++ * Reset interrupt transfers
++ */
++static void sl811_reset_interrupt(struct urb *urb)
++{
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td = urbp->cur_td;
++
++ PDEBUG(4, "enter, interval = %d", urb->interval);
++
++ td->ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
++ if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
++ td->ctrl |= SL811_USB_CTRL_TOGGLE_1;
++ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
++
++ sl811_reset_td(td);
++
++ urbp->interval = urb->interval;
++
++ urb->status = -EINPROGRESS;
++ urb->actual_length = 0;
++}
++
++/*
++ * Result the interrupt urb.
++ */
++static void sl811_result_interrupt(struct urb *urb)
++{
++ struct list_head *tmp;
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td;
++ int toggle;
++
++ PDEBUG(4, "enter, urb = %p", urb);
++
++ urb->actual_length = 0;
++
++ tmp = &urbp->td_list;
++ tmp = tmp->next;
++ td = list_entry(tmp, struct sl811_td, td_list);
++
++ // success.
++ if (td->done && td->td_status == 0) {
++ urb->actual_length += td->len - td->left;
++ urb->status = 0;
++ return ;
++ }
++ // tranfer is done but fail, reset the toggle.
++ else if (td->done && td->td_status) {
++ urb->status = td->td_status;
++reset_toggle:
++ toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0;
++ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle);
++ PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status);
++ return ;
++ }
++ // unlink, and not do transfer yet
++ else if (td->done == 0 && urbp->unlink && td->td_status == 0) {
++ urb->status = -ENOENT;
++ PDEBUG(3, "unlink and not transfer!");
++ return ;
++ }
++ // unlink, and transfer not complete yet.
++ else if (td->done == 0 && urbp->unlink && td->td_status) {
++ urb->status = -ENOENT;
++ PDEBUG(3, "unlink and not complete!");
++ goto reset_toggle;
++ }
++ // must be bug!!!
++ else {// (td->done == 0 && urbp->unlink == 0)
++ PDEBUG(1, "we should not get here!");
++ urb->status = -EPIPE;
++ return ;
++ }
++}
++
++/*
++ * Control transfers
++ */
++static int sl811_submit_control(struct urb *urb)
++{
++ int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
++ int len = urb->transfer_buffer_length;
++ __u8 *data = urb->transfer_buffer;
++ __u8 dev = usb_pipedevice(urb->pipe);
++ __u8 pidep = 0;
++ __u8 ctrl = 0;
++ struct sl811_hc *hc = urb->dev->bus->hcpriv;
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td = NULL;
++
++ PDEBUG(4, "enter, urb = %p", urb);
++
++ if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED))
++ ctrl |= SL811_USB_CTRL_PREAMBLE;
++
++ /* Build SETUP TD */
++ pidep = PIDEP(USB_PID_SETUP, usb_pipeendpoint(urb->pipe));
++ ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE | SL811_USB_CTRL_DIR_OUT;
++ td = sl811_alloc_td(urb);
++ if (!td)
++ return -ENOMEM;
++
++ sl811_fill_td(td, ctrl, SL811_DATA_START, 8, pidep, dev, urb->setup_packet);
++ sl811_calc_td_time(td);
++
++ urbp->cur_td = urbp->first_td = td;
++
++ /*
++ * If direction is "send", change the frame from SETUP (0x2D)
++ * to OUT (0xE1). Else change it from SETUP to IN (0x69).
++ */
++ pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
++ if (usb_pipeout(urb->pipe))
++ ctrl |= SL811_USB_CTRL_DIR_OUT;
++ else
++ ctrl &= ~SL811_USB_CTRL_DIR_OUT;
++
++ /* Build the DATA TD's */
++ while (len > 0) {
++ int pktsze = len;
++
++ if (pktsze > maxsze)
++ pktsze = maxsze;
++
++ /* Alternate Data0/1 (start with Data1) */
++ ctrl ^= SL811_USB_CTRL_TOGGLE_1;
++
++ td = sl811_alloc_td(urb);
++ if (!td)
++ return -ENOMEM;
++
++ sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data);
++ sl811_calc_td_time(td);
++
++ data += pktsze;
++ len -= pktsze;
++ }
++
++ /* Build the final TD for control status */
++ td = sl811_alloc_td(urb);
++ if (!td)
++ return -ENOMEM;
++
++ /* It's IN if the pipe is an output pipe or we're not expecting data back */
++ if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) {
++ pidep = PIDEP(USB_PID_IN, usb_pipeendpoint(urb->pipe));
++ ctrl &= ~SL811_USB_CTRL_DIR_OUT;
++ } else {
++ pidep = PIDEP(USB_PID_OUT, usb_pipeendpoint(urb->pipe));
++ ctrl |= SL811_USB_CTRL_DIR_OUT;
++ }
++
++ /* End in Data1 */
++ ctrl |= SL811_USB_CTRL_TOGGLE_1;
++
++ sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0);
++ sl811_calc_td_time(td);
++ urbp->last_td = td;
++/*
++// for debug
++ {
++ struct list_head *head, *tmp;
++ struct sl811_td *td;
++ int i = 0;
++ head = &urbp->td_list;
++ tmp = head->next;
++
++ if (list_empty(&urbp->td_list)) {
++ PDEBUG(1, "bug!!! td list is empty!");
++ return -ENODEV;
++ }
++
++ while (tmp != head) {
++ ++i;
++ td = list_entry(tmp, struct sl811_td, td_list);
++ PDEBUG(3, "td = %p, i = %d", td, i);
++ tmp = tmp->next;
++ }
++ }
++*/
++ PDEBUG(4, "leave success");
++
++ return 0;
++}
++
++/*
++ * Result the control urb.
++ */
++static void sl811_result_control(struct urb *urb)
++{
++ struct list_head *tmp, *head;
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td;
++
++ PDEBUG(4, "enter, urb = %p", urb);
++
++ if (list_empty(&urbp->td_list)) {
++ PDEBUG(1, "td list is empty");
++ return ;
++ }
++
++ head = &urbp->td_list;
++
++ tmp = head->next;
++ td = list_entry(tmp, struct sl811_td, td_list);
++
++ /* The first TD is the SETUP phase, check the status, but skip the count */
++ if (!td->done) {
++ PDEBUG(3, "setup phase error, td = %p, done = %d", td, td->done);
++ goto err_done;
++ }
++ if (td->td_status) {
++ PDEBUG(3, "setup phase error, td = %p, td status = %d", td, td->td_status);
++ goto err_status;
++ }
++
++ urb->actual_length = 0;
++
++ /* The rest of the TD's (but the last) are data */
++ tmp = tmp->next;
++ while (tmp != head && tmp->next != head) {
++ td = list_entry(tmp, struct sl811_td, td_list);
++ tmp = tmp->next;
++ if (!td->done) {
++ PDEBUG(3, "data phase error, td = %p, done = %d", td, td->done);
++ goto err_done;
++ }
++ if (td->td_status) {
++ PDEBUG(3, "data phase error, td = %p, td status = %d", td, td->td_status);
++ goto err_status;
++ }
++
++ urb->actual_length += td->len - td->left;
++ // short packet.
++ if (td->left) {
++ PDEBUG(3, "data phase short packet, td = %p, count = %d", td, td->len - td->left);
++ break;
++ }
++ }
++
++ /* The last td is status phase */
++ td = urbp->last_td;
++ if (!td->done) {
++ PDEBUG(3, "status phase error, td = %p, done = %d", td, td->done);
++ goto err_done;
++ }
++ if (td->td_status) {
++ PDEBUG(3, "status phase error, td = %p, td status = %d", td, td->td_status);
++ goto err_status;
++ }
++
++ PDEBUG(4, "leave success");
++
++ urb->status = 0;
++ return ;
++
++err_done:
++ if (urbp->unlink)
++ urb->status = -ENOENT;
++ else {
++ PDEBUG(1, "we should not get here! td = %p", td);
++ urb->status = -EPIPE;
++ }
++ return ;
++
++err_status:
++ urb->status = td->td_status;
++ return ;
++}
++
++/*
++ * Bulk transfers
++ */
++static int sl811_submit_bulk(struct urb *urb)
++{
++ int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
++ int len = urb->transfer_buffer_length;
++ __u8 *data = urb->transfer_buffer;
++ __u8 dev = usb_pipedevice(urb->pipe);
++ __u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
++ __u8 ctrl = 0;
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td = NULL;
++
++ PDEBUG(4, "enter, urb = %p", urb);
++
++ if (len < 0) {
++ PDEBUG(1, "error, urb = %p, len = %d", urb, len);
++ return -EINVAL;
++ }
++
++ /* Can't have low speed bulk transfers */
++ if (usb_pipeslow(urb->pipe)) {
++ PDEBUG(1, "error, urb = %p, low speed device", urb);
++ return -EINVAL;
++ }
++
++ if (usb_pipeout(urb->pipe))
++ ctrl |= SL811_USB_CTRL_DIR_OUT;
++
++ ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
++
++ /* Build the DATA TD's */
++ do { /* Allow zero length packets */
++ int pktsze = len;
++
++ if (pktsze > maxsze)
++ pktsze = maxsze;
++
++ td = sl811_alloc_td(urb);
++ if (!td)
++ return -ENOMEM;
++
++ /* Alternate Data0/1 (start with Data1) */
++ ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
++ if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
++ ctrl |= SL811_USB_CTRL_TOGGLE_1;
++ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
++
++ sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data);
++ sl811_calc_td_time(td);
++
++ if (urbp->cur_td == NULL)
++ urbp->cur_td = urbp->first_td = td;
++
++ data += pktsze;
++ len -= maxsze;
++ } while (len > 0);
++
++ /*
++ * USB_ZERO_PACKET means adding a 0-length packet, if
++ * direction is OUT and the transfer_length was an
++ * exact multiple of maxsze, hence
++ * (len = transfer_length - N * maxsze) == 0
++ * however, if transfer_length == 0, the zero packet
++ * was already prepared above.
++ */
++ if (usb_pipeout(urb->pipe) && (urb->transfer_flags & USB_ZERO_PACKET) &&
++ !len && urb->transfer_buffer_length) {
++
++ td = sl811_alloc_td(urb);
++ if (!td)
++ return -ENOMEM;
++
++ /* Alternate Data0/1 (start with Data1) */
++ ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
++ if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
++ ctrl |= SL811_USB_CTRL_TOGGLE_1;
++ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
++
++ sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0);
++ sl811_calc_td_time(td);
++ }
++
++ urbp->last_td = td;
++
++ PDEBUG(4, "leave success");
++
++ return 0;
++}
++
++/*
++ * Reset bulk transfers
++ */
++static int sl811_reset_bulk(struct urb *urb)
++{
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td;
++ struct list_head *head, *tmp;
++
++ PDEBUG(4, "enter, urb = %p", urb);
++
++
++ head = &urbp->td_list;
++ tmp = head->next;
++
++ while (tmp != head) {
++ td = list_entry(tmp, struct sl811_td, td_list);
++
++ /* Alternate Data0/1 (start with Data1) */
++ td->ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
++ if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
++ td->ctrl |= SL811_USB_CTRL_TOGGLE_1;
++ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
++
++ sl811_reset_td(td);
++ }
++
++ urb->status = -EINPROGRESS;
++ urb->actual_length = 0;
++ urbp->cur_td = urbp->first_td;
++
++ PDEBUG(4, "leave success");
++
++ return 0;
++}
++
++/*
++ * Result the bulk urb.
++ */
++static void sl811_result_bulk(struct urb *urb)
++{
++ struct list_head *tmp, *head;
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td = NULL;
++ int toggle;
++
++ PDEBUG(4, "enter, urb = %p", urb);
++
++ urb->actual_length = 0;
++
++ head = &urbp->td_list;
++ tmp = head->next;
++ while (tmp != head) {
++ td = list_entry(tmp, struct sl811_td, td_list);
++ tmp = tmp->next;
++
++ // success.
++ if (td->done && td->td_status == 0) {
++ urb->actual_length += td->len - td->left;
++
++ // short packet
++ if (td->left) {
++ urb->status = 0;
++ PDEBUG(3, "short packet, td = %p, count = %d", td, td->len - td->left);
++ goto reset_toggle;
++ }
++ }
++ // tranfer is done but fail, reset the toggle.
++ else if (td->done && td->td_status) {
++ urb->status = td->td_status;
++ PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status);
++ goto reset_toggle;
++ }
++ // unlink, and not do transfer yet
++ else if (td->done == 0 && urbp->unlink && td->td_status == 0) {
++ urb->status = -ENOENT;
++ PDEBUG(3, "unlink and not transfer!");
++ return ;
++ }
++ // unlink, and transfer not complete yet.
++ else if (td->done == 0 && urbp->unlink && td->td_status) {
++ PDEBUG(3, "unlink and not complete!");
++ urb->status = -ENOENT;
++ goto reset_toggle;
++ }
++ // must be bug!!!
++ else {// (td->done == 0 && urbp->unlink == 0)
++ urb->status = -EPIPE;
++ PDEBUG(1, "we should not get here!");
++ return ;
++ }
++ }
++
++ PDEBUG(4, "leave success");
++ urb->status = 0;
++ return ;
++
++reset_toggle:
++ toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0;
++ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle);
++}
++
++/*
++ * Find the first urb have the same dev and endpoint.
++ */
++static inline int sl811_find_same_urb(struct list_head *head, struct urb *urb)
++{
++ struct list_head *tmp;
++ struct urb *u;
++
++ if (!head || !urb)
++ return 0;
++
++ tmp = head->next;
++
++ while (tmp != head) {
++ u = list_entry(tmp, struct urb, urb_list);
++ if (u == urb)
++ return 1;
++ tmp = tmp->next;
++ }
++
++ return 0;
++}
++
++/*
++ * Find the first urb have the same dev and endpoint.
++ */
++static inline struct urb* sl811_find_same_devep(struct list_head *head, struct urb *urb)
++{
++ struct list_head *tmp;
++ struct urb *u;
++
++ if (!head || !urb)
++ return NULL;
++
++ tmp = head->next;
++
++ while (tmp != head) {
++ u = list_entry(tmp, struct urb, urb_list);
++ if ((usb_pipe_endpdev(u->pipe)) == (usb_pipe_endpdev(urb->pipe)))
++ return u;
++ tmp = tmp->next;
++ }
++
++ return NULL;
++}
++
++/*
++ * This function is called by the USB core API when an URB is available to
++ * process.
++ */
++static int sl811_submit_urb(struct urb *urb)
++{
++ struct sl811_hc *hc = urb->dev->bus->hcpriv;
++ unsigned int pipe = urb->pipe;
++ struct list_head *head = NULL;
++ unsigned long flags;
++ int bustime;
++ int ret = 0;
++
++ if (!urb) {
++ PDEBUG(1, "urb is null");
++ return -EINVAL;
++ }
++
++ if (urb->hcpriv) {
++ PDEBUG(1, "urbp is not null, urb = %p, urbp = %p", urb, urb->hcpriv);
++ return -EINVAL;
++ }
++
++ if (!urb->dev || !urb->dev->bus || !hc) {
++ PDEBUG(1, "dev or bus or hc is null");
++ return -ENODEV;
++ }
++
++ if (usb_endpoint_halted(urb->dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
++ PDEBUG(2, "sl811_submit_urb: endpoint_halted");
++ return -EPIPE;
++ }
++
++ if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) > SL811_DATA_LIMIT) {
++ printk(KERN_ERR "Packet size is big for SL811, should < %d!\n", SL811_DATA_LIMIT);
++ return -EINVAL;
++ }
++
++ /* a request to the virtual root hub */
++ if (usb_pipedevice(pipe) == hc->rh.devnum)
++ return sl811_rh_submit_urb(urb);
++
++ spin_lock_irqsave(&hc->hc_lock, flags);
++ spin_lock(&urb->lock);
++
++ switch (usb_pipetype(urb->pipe)) {
++ case PIPE_ISOCHRONOUS:
++ head = &hc->iso_list;
++ break;
++ case PIPE_INTERRUPT:
++ head = &hc->intr_list;
++ break;
++ case PIPE_CONTROL:
++ head = &hc->ctrl_list;
++ break;
++ case PIPE_BULK:
++ head = &hc->bulk_list;
++ break;
++ }
++
++ if (sl811_find_same_devep(head, urb)) {
++ list_add(&urb->urb_list, &hc->wait_list);
++ PDEBUG(4, "add to wait list");
++ goto out_unlock;
++ }
++
++ if (!sl811_alloc_urb_priv(urb)) {
++ ret = -ENOMEM;
++ goto out_unlock;
++ }
++
++ switch (usb_pipetype(urb->pipe)) {
++ case PIPE_ISOCHRONOUS:
++ if (urb->number_of_packets <= 0) {
++ ret = -EINVAL;
++ break;
++ }
++ bustime = usb_check_bandwidth(urb->dev, urb);
++ if (bustime < 0) {
++ ret = bustime;
++ break;
++ }
++ if (!(ret = sl811_submit_isochronous(urb)))
++ usb_claim_bandwidth(urb->dev, urb, bustime, 1);
++ break;
++ case PIPE_INTERRUPT:
++ bustime = usb_check_bandwidth(urb->dev, urb);
++ if (bustime < 0)
++ ret = bustime;
++ else if (!(ret = sl811_submit_interrupt(urb)))
++ usb_claim_bandwidth(urb->dev, urb, bustime, 0);
++ break;
++ case PIPE_CONTROL:
++ ret = sl811_submit_control(urb);
++ break;
++ case PIPE_BULK:
++ ret = sl811_submit_bulk(urb);
++ break;
++ }
++
++ if (!ret) {
++ ((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies;
++ list_add(&urb->urb_list, head);
++ PDEBUG(4, "add to type list");
++ urb->status = -EINPROGRESS;
++ if (++hc->active_urbs == 1)
++ sl811_enable_interrupt(hc);
++ goto out_unlock;
++ } else {
++ PDEBUG(2, "submit urb fail! error = %d", ret);
++ sl811_free_urb_priv(urb);
++ }
++
++out_unlock:
++ spin_unlock(&urb->lock);
++ spin_unlock_irqrestore(&hc->hc_lock, flags);
++
++ return ret;
++}
++
++/*
++ * Submit the urb the wait list.
++ */
++static int sl811_submit_urb_with_lock(struct urb *urb)
++{
++ struct sl811_hc *hc = urb->dev->bus->hcpriv;
++ struct list_head *head = NULL;
++ int bustime;
++ int ret = 0;
++
++ spin_lock(&urb->lock);
++
++ switch (usb_pipetype(urb->pipe)) {
++ case PIPE_ISOCHRONOUS:
++ head = &hc->iso_list;
++ break;
++ case PIPE_INTERRUPT:
++ head = &hc->intr_list;
++ break;
++ case PIPE_CONTROL:
++ head = &hc->ctrl_list;
++ break;
++ case PIPE_BULK:
++ head = &hc->bulk_list;
++ break;
++ }
++
++ if (!sl811_alloc_urb_priv(urb)) {
++ ret = -ENOMEM;
++ goto out_unlock;
++ }
++
++ switch (usb_pipetype(urb->pipe)) {
++ case PIPE_ISOCHRONOUS:
++ if (urb->number_of_packets <= 0) {
++ ret = -EINVAL;
++ break;
++ }
++ bustime = usb_check_bandwidth(urb->dev, urb);
++ if (bustime < 0) {
++ ret = bustime;
++ break;
++ }
++ if (!(ret = sl811_submit_isochronous(urb)))
++ usb_claim_bandwidth(urb->dev, urb, bustime, 1);
++ break;
++ case PIPE_INTERRUPT:
++ bustime = usb_check_bandwidth(urb->dev, urb);
++ if (bustime < 0)
++ ret = bustime;
++ else if (!(ret = sl811_submit_interrupt(urb)))
++ usb_claim_bandwidth(urb->dev, urb, bustime, 0);
++ break;
++ case PIPE_CONTROL:
++ ret = sl811_submit_control(urb);
++ break;
++ case PIPE_BULK:
++ ret = sl811_submit_bulk(urb);
++ break;
++ }
++
++ if (ret == 0) {
++ ((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies;
++ list_add(&urb->urb_list, head);
++ PDEBUG(4, "add to type list");
++ urb->status = -EINPROGRESS;
++ if (++hc->active_urbs == 1)
++ sl811_enable_interrupt(hc);
++ goto out_unlock;
++ } else {
++ PDEBUG(2, "submit urb fail! error = %d", ret);
++ sl811_free_urb_priv(urb);
++ }
++
++out_unlock:
++ spin_unlock(&urb->lock);
++
++ return ret;
++}
++
++/*
++ * Reset the urb
++ */
++static void sl811_reset_urb(struct urb *urb)
++{
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++
++ switch (usb_pipetype(urb->pipe)) {
++ case PIPE_ISOCHRONOUS:
++ sl811_reset_isochronous(urb);
++ break;
++ case PIPE_INTERRUPT:
++ sl811_reset_interrupt(urb);
++ break;
++ case PIPE_CONTROL:
++ return;
++ case PIPE_BULK:
++ sl811_reset_bulk(urb);
++ break;
++ }
++ urbp->inserttime = jiffies;
++}
++
++/*
++ * Return the result of a transfer
++ */
++static void sl811_result_urb(struct urb *urb)
++{
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_hc *hc = urb->dev->bus->hcpriv;
++ struct list_head *head = NULL;
++ struct urb *u = NULL;
++ int reset = 0;
++ int ring = 0;
++
++ if (urb->status != -EINPROGRESS) {
++ PDEBUG(1, "urb status is not EINPROGRESS!");
++ return ;
++ }
++
++ spin_lock(&urb->lock);
++
++ switch (usb_pipetype(urb->pipe)) {
++ case PIPE_ISOCHRONOUS:
++ head = &hc->iso_list;
++ sl811_result_isochronous(urb);
++
++ // if the urb is not unlink and is in a urb "ring", we reset it
++ if (!urbp->unlink && urb->next)
++ ring = 1;
++ break;
++ case PIPE_INTERRUPT:
++ head = &hc->intr_list;
++ sl811_result_interrupt(urb);
++
++ // if the urb is not unlink and not "once" query, we reset.
++ if (!urbp->unlink && urb->interval)
++ reset = 1;
++ break;
++ case PIPE_CONTROL:
++ head = &hc->ctrl_list;
++ sl811_result_control(urb);
++ break;
++ case PIPE_BULK:
++ head = &hc->bulk_list;
++ sl811_result_bulk(urb);
++
++ // if the urb is not unlink and is in a urb "ring", we reset it
++ if (!urbp->unlink && urb->next)
++ ring = 1;
++ break;
++ }
++
++ PDEBUG(4, "result urb status = %d", urb->status);
++
++ if (ring && urb->next == urb)
++ reset = 1;
++
++ if (!reset) {
++ switch (usb_pipetype(urb->pipe)) {
++ case PIPE_ISOCHRONOUS:
++ usb_release_bandwidth(urb->dev, urb, 1);
++ break;
++ case PIPE_INTERRUPT:
++ usb_release_bandwidth(urb->dev, urb, 0);
++ break;
++ }
++ sl811_free_urb_priv(urb);
++ }
++
++ spin_unlock(&urb->lock);
++
++ if (urb->complete)
++ urb->complete(urb);
++
++ if (reset) {
++ spin_lock(&urb->lock);
++ sl811_reset_urb(urb);
++ if (usb_pipeint(urb->pipe))
++ list_add(&urb->urb_list, &hc->idle_intr_list);
++ else
++ list_add(&urb->urb_list, head);
++ spin_unlock(&urb->lock);
++ } else {
++ if (--hc->active_urbs <= 0) {
++ hc->active_urbs = 0;
++ sl811_disable_interrupt(hc);
++ }
++
++ if (ring)
++ u = urb->next;
++ else
++ u = sl811_find_same_devep(&hc->wait_list, urb);
++
++ if (u) {
++ if (!list_empty(&u->urb_list))
++ list_del(&u->urb_list);
++ if (sl811_submit_urb_with_lock(u))
++ list_add(&u->urb_list, &hc->wait_list);
++ }
++ }
++}
++
++
++#ifdef SL811_TIMEOUT
++
++/*
++ * Unlink the urb from the urb list
++ */
++static int sl811_unlink_urb(struct urb *urb)
++{
++ unsigned long flags;
++ struct sl811_hc *hc;
++ struct sl811_urb_priv *urbp;
++ int call = 0;
++ int schedule = 0;
++ int count = 0;
++
++ if (!urb) {
++ PDEBUG(1, "urb is null");
++ return -EINVAL;
++ }
++
++ if (!urb->dev || !urb->dev->bus) {
++ PDEBUG(1, "dev or bus is null");
++ return -ENODEV;
++ }
++
++ hc = urb->dev->bus->hcpriv;
++ urbp = urb->hcpriv;
++
++ /* a request to the virtual root hub */
++ if (usb_pipedevice(urb->pipe) == hc->rh.devnum)
++ return sl811_rh_unlink_urb(urb);
++
++ spin_lock_irqsave(&hc->hc_lock, flags);
++ spin_lock(&urb->lock);
++
++ // in wait list
++ if (sl811_find_same_urb(&hc->wait_list, urb)) {
++ PDEBUG(4, "unlink urb in wait list");
++ list_del_init(&urb->urb_list);
++ urb->status = -ENOENT;
++ call = 1;
++ goto out;
++ }
++
++ // in intr idle list.
++ if (sl811_find_same_urb(&hc->idle_intr_list, urb)) {
++ PDEBUG(4, "unlink urb in idle intr list");
++ list_del_init(&urb->urb_list);
++ urb->status = -ENOENT;
++ sl811_free_urb_priv(urb);
++ usb_release_bandwidth(urb->dev, urb, 0);
++ if (--hc->active_urbs <= 0) {
++ hc->active_urbs = 0;
++ sl811_disable_interrupt(hc);
++ }
++ call = 1;
++ goto out;
++ }
++
++ if (urb->status == -EINPROGRESS) {
++ PDEBUG(3, "urb is still in progress");
++ urbp->unlink = 1;
++
++re_unlink:
++ // Is it in progress?
++ urbp = urb->hcpriv;
++ if (urbp && hc->cur_td == urbp->cur_td) {
++ ++count;
++ if (sl811_read(hc, 0) & SL811_USB_CTRL_ARM) {
++ PDEBUG(3, "unlink: cur td is still in progress! count = %d", count);
++re_schedule:
++ schedule = 1;
++ spin_unlock(&urb->lock);
++ spin_unlock_irqrestore(&hc->hc_lock, flags);
++ schedule_timeout(HZ/50);
++ spin_lock_irqsave(&hc->hc_lock, flags);
++ spin_lock(&urb->lock);
++ } else {
++ PDEBUG(3, "unlink: lost of interrupt? do parse! count = %d", count);
++ spin_unlock(&urb->lock);
++ sl811_transfer_done(hc, 0);
++ spin_lock(&urb->lock);
++ }
++ goto re_unlink;
++ }
++
++ if (list_empty(&urb->urb_list)) {
++ PDEBUG(3, "unlink: list empty!");
++ goto out;
++ }
++
++ if (urb->transfer_flags & USB_TIMEOUT_KILLED) {
++ PDEBUG(3, "unlink: time out killed");
++ // it is timeout killed by us
++ goto result;
++ } else if (urb->transfer_flags & USB_ASYNC_UNLINK) {
++ // we do nothing, just let it be processing later
++ PDEBUG(3, "unlink async, do nothing");
++ goto out;
++ } else {
++ // synchron without callback
++ PDEBUG(3, "unlink synchron, we wait the urb complete or timeout");
++ if (schedule == 0) {
++ PDEBUG(3, "goto re_schedule");
++ goto re_schedule;
++ } else {
++ PDEBUG(3, "already scheduled");
++ goto result;
++ }
++ }
++ } else if (!list_empty(&urb->urb_list)) {
++ PDEBUG(1, "urb = %p, status = %d is in a list, why?", urb, urb->status);
++ //list_del_init(&urb->urb_list);
++ //call = 1;
++ }
++
++out:
++ spin_unlock(&urb->lock);
++ spin_unlock_irqrestore(&hc->hc_lock, flags);
++
++ if (call && urb->complete)
++ urb->complete(urb);
++
++ return 0;
++
++result:
++ spin_unlock(&urb->lock);
++
++ list_del_init(&urb->urb_list);
++ sl811_result_urb(urb);
++
++ spin_unlock_irqrestore(&hc->hc_lock, flags);
++
++ return 0;
++}
++
++#else
++
++/*
++ * Unlink the urb from the urb list
++ */
++static int sl811_unlink_urb(struct urb *urb)
++{
++ unsigned long flags;
++ struct sl811_hc *hc;
++ struct sl811_urb_priv *urbp;
++ int call = 0;
++
++ if (!urb) {
++ PDEBUG(1, "urb is null");
++ return -EINVAL;
++ }
++
++ if (!urb->dev || !urb->dev->bus) {
++ PDEBUG(1, "dev or bus is null");
++ return -ENODEV;
++ }
++
++ hc = urb->dev->bus->hcpriv;
++ urbp = urb->hcpriv;
++
++ /* a request to the virtual root hub */
++ if (usb_pipedevice(urb->pipe) == hc->rh.devnum)
++ return sl811_rh_unlink_urb(urb);
++
++ spin_lock_irqsave(&hc->hc_lock, flags);
++ spin_lock(&urb->lock);
++
++ // in wait list
++ if (sl811_find_same_urb(&hc->wait_list, urb)) {
++ PDEBUG(2, "unlink urb in wait list");
++ list_del_init(&urb->urb_list);
++ urb->status = -ENOENT;
++ call = 1;
++ goto out;
++ }
++
++ if (urb->status == -EINPROGRESS) {
++ PDEBUG(2, "urb is still in progress");
++ urbp->unlink = 1;
++
++ // Is it in progress?
++ urbp = urb->hcpriv;
++ if (urbp && hc->cur_td == urbp->cur_td) {
++ // simple, let it out
++ PDEBUG(2, "unlink: cur td is still in progress!");
++ hc->cur_td = NULL;
++ }
++
++ goto result;
++ } else if (!list_empty(&urb->urb_list)) {
++ PDEBUG(1, "urb = %p, status = %d is in a list, why?", urb, urb->status);
++ list_del_init(&urb->urb_list);
++ if (urbp)
++ goto result;
++ else
++ call = 1;
++ }
++
++out:
++ spin_unlock(&urb->lock);
++ spin_unlock_irqrestore(&hc->hc_lock, flags);
++
++ if (call && urb->complete)
++ urb->complete(urb);
++
++ return 0;
++
++result:
++ spin_unlock(&urb->lock);
++
++ list_del_init(&urb->urb_list);
++ sl811_result_urb(urb);
++
++ spin_unlock_irqrestore(&hc->hc_lock, flags);
++
++ return 0;
++}
++
++#endif
++
++static int sl811_get_current_frame_number(struct usb_device *usb_dev)
++{
++ return ((struct sl811_hc *)(usb_dev->bus->hcpriv))->frame_number;
++}
++
++static struct usb_operations sl811_device_operations =
++{
++ sl811_alloc_dev_priv,
++ sl811_free_dev_priv,
++ sl811_get_current_frame_number,
++ sl811_submit_urb,
++ sl811_unlink_urb
++};
++
++/*
++ * This functions transmit a td.
++ */
++static inline void sl811_trans_cur_td(struct sl811_hc *hc, struct sl811_td *td)
++{
++ sl811_print_td(4, td);
++ sl811_write_buf(hc, SL811_ADDR_A, &td->addr, 4);
++ if (td->len && (td->ctrl & SL811_USB_CTRL_DIR_OUT))
++ sl811_write_buf(hc, td->addr, td->buf, td->len);
++
++ sl811_write(hc, SL811_CTRL_A, td->ctrl);
++}
++
++
++/*
++ * This function checks the status of the transmitted or received packet
++ * and copy the data from the SL811HS register into a buffer.
++ */
++static void sl811_parse_cur_td(struct sl811_hc *hc, struct sl811_td *td)
++{
++ struct urb *urb = td->urb;
++#ifdef SL811_DEBUG
++ int dev = usb_pipedevice(td->urb->pipe);
++ int ep = usb_pipeendpoint(td->urb->pipe);
++#endif
++
++ sl811_read_buf(hc, SL811_STS_A, &td->status, 2);
++
++ if (td->status & SL811_USB_STS_ACK) {
++ td->done = 1;
++
++/* if ((td->ctrl & SL811_USB_CTRL_TOGGLE_1) != (td->status & SL811_USB_STS_TOGGLE_1)) {
++ PDEBUG(2, "dev %d endpoint %d unexpect data toggle!", dev, ep);
++ td->td_status = -EILSEQ;
++ }
++*/
++ if (!(td->ctrl & SL811_USB_CTRL_DIR_OUT) && td->len > 0)
++ sl811_read_buf(hc, td->addr, td->buf, td->len - td->left);
++
++ if (td->left && (urb->transfer_flags & USB_DISABLE_SPD)) {
++ PDEBUG(2, "dev %d endpoint %d unexpect short packet! td = %p", dev, ep, td);
++ td->td_status = -EREMOTEIO;
++ } else
++ td->td_status = 0;
++ } else if (td->status & SL811_USB_STS_STALL) {
++ PDEBUG(2, "dev %d endpoint %d halt, td = %p", dev, ep, td);
++ td->td_status = -EPIPE;
++ if (urb->dev)
++ usb_endpoint_halt(td->urb->dev, usb_pipeendpoint(td->urb->pipe), usb_pipeout(td->urb->pipe));
++ td->done = 1;
++ } else if (td->status & SL811_USB_STS_OVERFLOW) {
++ PDEBUG(1, "dev %d endpoint %d overflow, sl811 only support packet less than %d", dev, ep, SL811_DATA_LIMIT);
++ td->td_status = -EOVERFLOW;
++ td->done = 1;
++ } else if (td->status & SL811_USB_STS_TIMEOUT ) {
++ PDEBUG(2, "dev %d endpoint %d timeout, td = %p", dev, ep, td);
++ td->td_status = -ETIMEDOUT;
++ if (--td->errcnt == 0)
++ td->done = 1;
++ } else if (td->status & SL811_USB_STS_ERROR) {
++ PDEBUG(2, "dev %d endpoint %d error, td = %p", dev, ep, td);
++ td->td_status = -EILSEQ;
++ if (--td->errcnt == 0)
++ td->done = 1;
++ } else if (td->status & SL811_USB_STS_NAK) {
++ ++td->nakcnt;
++ PDEBUG(3, "dev %d endpoint %d nak, td = %p, count = %d", dev, ep, td, td->nakcnt);
++ td->td_status = -EINPROGRESS;
++ if (!usb_pipeslow(td->urb->pipe) && td->nakcnt > 1024) {
++ PDEBUG(2, "too many naks, td = %p, count = %d", td, td->nakcnt);
++ td->td_status = -ETIMEDOUT;
++ td->done = 1;
++ }
++ }
++
++ sl811_print_td(4, td);
++}
++
++/*
++ * This function checks the status of current urb.
++ */
++static int sl811_parse_cur_urb(struct urb *urb)
++{
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++ struct sl811_td *td = urbp->cur_td;
++ struct list_head *tmp;
++
++ sl811_print_td(5, td);
++
++ // this td not done yet.
++ if (!td->done)
++ return 0;
++
++ // the last ld, so the urb is done.
++ if (td == urbp->last_td) {
++ PDEBUG(4, "urb = %p is done success", td->urb);
++ if (usb_pipeisoc(td->urb->pipe))
++ PDEBUG(4, "ISO URB DONE, td = %p", td);
++ return 1;
++ }
++
++ // iso transfer, we always advance to next td
++ if (usb_pipeisoc(td->urb->pipe)) {
++ tmp = &td->td_list;
++ tmp = tmp->next;
++ urbp->cur_td = list_entry(tmp, struct sl811_td, td_list);
++ PDEBUG(4, "ISO NEXT, td = %p", urbp->cur_td);
++ return 0;
++ }
++
++ // some error occur, so the urb is done.
++ if (td->td_status) {
++ PDEBUG(3, "urb = %p is done error, td status is = %d", td->urb, td->td_status);
++ return 1;
++ }
++
++ // short packet.
++ if (td->left) {
++ if (usb_pipecontrol(td->urb->pipe)) {
++ // control packet, we advance to the last td
++ PDEBUG(3, "ctrl short packet, advance to last td");
++ urbp->cur_td = urbp->last_td;
++ return 0;
++ } else {
++ // interrut and bulk packet, urb is over.
++ PDEBUG(3, "bulk or intr short packet, urb is over");
++ return 1;
++ }
++ }
++
++ // we advance to next td.
++ tmp = &td->td_list;
++ tmp = tmp->next;
++ urbp->cur_td = list_entry(tmp, struct sl811_td, td_list);
++#ifdef SL811_DEBUG
++ PDEBUG(4, "advance to the next td, urb = %p, td = %p", urb, urbp->cur_td);
++ sl811_print_td(5, urbp->cur_td);
++ if (td == urbp->cur_td)
++ PDEBUG(1, "bug!!!");
++#endif
++ return 0;
++}
++
++/*
++ * Find the next td to transfer.
++ */
++static inline struct sl811_td* sl811_schedule_next_td(struct urb *urb, struct sl811_td *cur_td)
++{
++ struct sl811_urb_priv *urbp = urb->hcpriv;
++
++ PDEBUG(4, "urb at %p, cur td at %p", urb, cur_td);
++
++ // iso don't schedule the td in the same frame.
++ if (usb_pipeisoc(cur_td->urb->pipe))
++ return NULL;
++
++ // cur td is not complete
++ if (!cur_td->done)
++ return NULL;
++
++ // here, urbp->cur_td is already the next td;
++ return urbp->cur_td;
++}
++
++/*
++ * Scan the list to find a active urb
++ */
++static inline struct urb* sl811_get_list_next_urb(struct sl811_hc *hc, struct list_head *next)
++{
++ struct urb *urb;
++ int i;
++
++ if (list_empty(next))
++ return NULL;
++
++ if (next == hc->cur_list)
++ return NULL;
++
++ for (i = 0; i < 4; ++i)
++ if (next == &hc->urb_list[i])
++ return NULL;
++
++ urb = list_entry(next, struct urb, urb_list);
++ PDEBUG(4, "next urb in list is at %p", urb);
++
++ return urb;
++}
++
++/*
++ * Find the next td to transfer.
++ */
++static struct sl811_td* sl811_schedule_next_urb(struct sl811_hc *hc, struct list_head *next)
++{
++ struct urb *urb = NULL;
++ int back_loop = 1;
++ struct list_head *old_list = hc->cur_list;
++
++ // try to get next urb in the same list.
++ if (next) {
++ urb = sl811_get_list_next_urb(hc, next);
++ if (!urb)
++ ++hc->cur_list;
++ }
++
++ // try other list.
++ if (!urb) {
++re_loop:
++ // try all the list.
++ while (hc->cur_list < &hc->urb_list[4]) {
++ if ((urb = sl811_get_list_next_urb(hc, hc->cur_list->next)))
++ return ((struct sl811_urb_priv *)urb->hcpriv)->cur_td;
++ ++hc->cur_list;
++ }
++ // the last list is try
++ if (back_loop && (old_list >= &hc->ctrl_list)) {
++ hc->cur_list = &hc->ctrl_list;
++ back_loop = 0;
++ goto re_loop;
++ }
++ }
++
++ if (hc->cur_list > &hc->urb_list[3])
++ hc->cur_list = &hc->ctrl_list;
++
++ return NULL;
++}
++
++/*
++ * This function process the transfer rusult.
++ */
++static void sl811_transfer_done(struct sl811_hc *hc, int sof)
++{
++ struct sl811_td *cur_td = hc->cur_td, *next_td = NULL;
++ struct urb *cur_urb = NULL;
++ struct list_head *next = NULL;
++ int done;
++
++ PDEBUG(5, "enter");
++
++ if (cur_td == NULL) {
++ PDEBUG(1, "in done interrupt, but td is null, be already parsed?");
++ return ;
++ }
++
++ cur_urb = cur_td->urb;
++ hc->cur_td = NULL;
++ next = &cur_urb->urb_list;
++ next = next->next;
++
++ spin_lock(&cur_urb->lock);
++ sl811_parse_cur_td(hc, cur_td);
++ done = sl811_parse_cur_urb(cur_urb);
++ spin_unlock(&cur_urb->lock);
++
++ if (done) {
++ list_del_init(&cur_urb->urb_list);
++ cur_td = NULL;
++ sl811_result_urb(cur_urb);
++ }
++
++ if (sof)
++ return ;
++
++ if (!done) {
++ next_td = sl811_schedule_next_td(cur_urb, cur_td);
++ if (next_td && next_td != cur_td && (sl811_calc_bus_remainder(hc) > next_td->bustime)) {
++ hc->cur_td = next_td;
++ PDEBUG(5, "ADD TD");
++ sl811_trans_cur_td(hc, next_td);
++ return ;
++ }
++ }
++
++ while (1) {
++ next_td = sl811_schedule_next_urb(hc, next);
++ if (!next_td)
++ return;
++ if (next_td == cur_td)
++ return;
++ next = &next_td->urb->urb_list;
++ next = next->next;
++ if (sl811_calc_bus_remainder(hc) > next_td->bustime) {
++ hc->cur_td = next_td;
++ PDEBUG(5, "ADD TD");
++ sl811_trans_cur_td(hc, next_td);
++ return ;
++ }
++ }
++}
++
++/*
++ *
++ */
++static void inline sl811_dec_intr_interval(struct sl811_hc *hc)
++{
++ struct list_head *head, *tmp;
++ struct urb *urb;
++ struct sl811_urb_priv *urbp;
++
++ if (list_empty(&hc->idle_intr_list))
++ return ;
++
++ head = &hc->idle_intr_list;
++ tmp = head->next;
++
++ while (tmp != head) {
++ urb = list_entry(tmp, struct urb, urb_list);
++ tmp = tmp->next;
++ spin_lock(&urb->lock);
++ urbp = urb->hcpriv;
++ if (--urbp->interval == 0) {
++ list_del(&urb->urb_list);
++ list_add(&urb->urb_list, &hc->intr_list);
++ PDEBUG(4, "intr urb active");
++ }
++ spin_unlock(&urb->lock);
++ }
++}
++
++/*
++ * The sof interrupt is happen.
++ */
++static void sl811_start_sof(struct sl811_hc *hc)
++{
++ struct sl811_td *next_td;
++#ifdef SL811_DEBUG
++ static struct sl811_td *repeat_td = NULL;
++ static int repeat_cnt = 1;
++#endif
++ if (++hc->frame_number > 1024)
++ hc->frame_number = 0;
++
++ if (hc->active_urbs == 0)
++ return ;
++
++ sl811_dec_intr_interval(hc);
++
++ if (hc->cur_td) {
++ if (sl811_read(hc, 0) & SL811_USB_CTRL_ARM) {
++#ifdef SL811_DEBUG
++ if (repeat_td == hc->cur_td)
++ ++repeat_cnt;
++ else {
++ if (repeat_cnt >= 2)
++ PDEBUG(2, "cur td = %p repeat %d", hc->cur_td, repeat_cnt);
++ repeat_cnt = 1;
++ repeat_td = hc->cur_td;
++ }
++#endif
++ return ;
++ } else {
++ PDEBUG(2, "lost of interrupt in sof? do parse!");
++ sl811_transfer_done(hc, 1);
++
++ // let this frame idle
++ return;
++ }
++ }
++
++ hc->cur_list = &hc->iso_list;
++
++ if (hc->active_urbs == 0)
++ return ;
++
++ next_td = sl811_schedule_next_urb(hc, NULL);
++ if (!next_td) {
++#ifdef SL811_DEBUG
++ if (list_empty(&hc->idle_intr_list))
++ PDEBUG(2, "not schedule a td, why? urbs = %d", hc->active_urbs);
++#endif
++ return;
++ }
++ if (sl811_calc_bus_remainder(hc) > next_td->bustime) {
++ hc->cur_td = next_td;
++ sl811_trans_cur_td(hc, next_td);
++ } else
++ PDEBUG(2, "bus time if not enough, why?");
++}
++
++/*
++ * This function resets SL811HS controller and detects the speed of
++ * the connecting device
++ *
++ * Return: 0 = no device attached; 1 = USB device attached
++ */
++static int sl811_hc_reset(struct sl811_hc *hc)
++{
++ int status ;
++
++ sl811_write(hc, SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
++ sl811_write(hc, SL811_CTRL1, SL811_CTRL1_RESET);
++
++ mdelay(20);
++
++ // Disable hardware SOF generation, clear all irq status.
++ sl811_write(hc, SL811_CTRL1, 0);
++ mdelay(2);
++ sl811_write(hc, SL811_INTRSTS, 0xff);
++ status = sl811_read(hc, SL811_INTRSTS);
++
++ if (status & SL811_INTR_NOTPRESENT) {
++ // Device is not present
++ PDEBUG(0, "Device not present");
++ hc->rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE);
++ hc->rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
++ sl811_write(hc, SL811_INTR, SL811_INTR_INSRMV);
++ return 0;
++ }
++
++ // Send SOF to address 0, endpoint 0.
++ sl811_write(hc, SL811_LEN_B, 0);
++ sl811_write(hc, SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0));
++ sl811_write(hc, SL811_DEV_B, 0x00);
++ sl811_write (hc, SL811_SOFLOW, SL811_12M_HI);
++
++ if (status & SL811_INTR_SPEED_FULL) {
++ /* full speed device connect directly to root hub */
++ PDEBUG (0, "Full speed Device attached");
++
++ sl811_write(hc, SL811_CTRL1, SL811_CTRL1_RESET);
++ mdelay(20);
++ sl811_write(hc, SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
++ sl811_write(hc, SL811_CTRL1, SL811_CTRL1_SOF);
++
++ /* start the SOF or EOP */
++ sl811_write(hc, SL811_CTRL_B, SL811_USB_CTRL_ARM);
++ hc->rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION;
++ hc->rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
++ mdelay(2);
++ sl811_write (hc, SL811_INTRSTS, 0xff);
++ } else {
++ /* slow speed device connect directly to root-hub */
++ PDEBUG(0, "Low speed Device attached");
++
++ sl811_write(hc, SL811_CTRL1, SL811_CTRL1_RESET);
++ mdelay(20);
++ sl811_write(hc, SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI);
++ sl811_write(hc, SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF);
++
++ /* start the SOF or EOP */
++ sl811_write(hc, SL811_CTRL_B, SL811_USB_CTRL_ARM);
++ hc->rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED;
++ mdelay(2);
++ sl811_write(hc, SL811_INTRSTS, 0xff);
++ }
++
++ hc->rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
++ sl811_write(hc, SL811_INTR, SL811_INTR_INSRMV);
++
++ return 1;
++}
++
++/*
++ * Interrupt service routine.
++ */
++static void sl811_interrupt(int irq, void *__hc, struct pt_regs * r)
++{
++ __u8 status;
++ struct sl811_hc *hc = __hc;
++
++ status = sl811_read(hc, SL811_INTRSTS);
++ if (status == 0)
++ return ; /* Not me */
++
++ sl811_write(hc, SL811_INTRSTS, 0xff);
++
++ if (status & SL811_INTR_INSRMV) {
++ sl811_write(hc, SL811_INTR, 0);
++ sl811_write(hc, SL811_CTRL1, 0);
++ // wait for device stable
++ mdelay(100);
++ sl811_hc_reset(hc);
++ return ;
++ }
++
++ spin_lock(&hc->hc_lock);
++
++ if (status & SL811_INTR_DONE_A) {
++ if (status & SL811_INTR_SOF) {
++ sl811_transfer_done(hc, 1);
++ PDEBUG(4, "sof in done!");
++ sl811_start_sof(hc);
++ } else
++ sl811_transfer_done(hc, 0);
++ } else if (status & SL811_INTR_SOF)
++ sl811_start_sof(hc);
++
++ spin_unlock(&hc->hc_lock);
++
++ return ;
++}
++
++/*
++ * This function allocates all data structure and store in the
++ * private data structure.
++ *
++ * Return value : data structure for the host controller
++ */
++static struct sl811_hc* __devinit sl811_alloc_hc(void)
++{
++ struct sl811_hc *hc;
++ struct usb_bus *bus;
++ int i;
++
++ PDEBUG(4, "enter");
++
++ hc = (struct sl811_hc *)kmalloc(sizeof(struct sl811_hc), GFP_KERNEL);
++ if (!hc)
++ return NULL;
++
++ memset(hc, 0, sizeof(struct sl811_hc));
++
++ hc->rh_status.wPortStatus = USB_PORT_STAT_POWER;
++ hc->rh_status.wPortChange = 0;
++
++ hc->active_urbs = 0;
++ INIT_LIST_HEAD(&hc->hc_hcd_list);
++ list_add(&hc->hc_hcd_list, &sl811_hcd_list);
++
++ init_waitqueue_head(&hc->waitq);
++
++ for (i = 0; i < 6; ++i)
++ INIT_LIST_HEAD(&hc->urb_list[i]);
++
++ hc->cur_list = &hc->iso_list;
++
++ bus = usb_alloc_bus(&sl811_device_operations);
++ if (!bus) {
++ kfree (hc);
++ return NULL;
++ }
++
++ hc->bus = bus;
++ bus->bus_name = MODNAME;
++ bus->hcpriv = hc;
++
++ return hc;
++}
++
++/*
++ * This function De-allocate all resources
++ */
++static void sl811_release_hc(struct sl811_hc *hc)
++{
++ PDEBUG(4, "enter");
++
++ /* disconnect all devices */
++ if (hc->bus->root_hub)
++ usb_disconnect(&hc->bus->root_hub);
++
++ // Stop interrupt handle
++ if (hc->irq)
++ free_irq(hc->irq, hc);
++ hc->irq = 0;
++
++ /* Stop interrupt for sharing */
++ if (hc->addr_io) {
++ /* Disable Interrupts */
++ sl811_write(hc, SL811_INTR, 0);
++
++ /* Remove all Interrupt events */
++ mdelay(2);
++ sl811_write(hc, SL811_INTRSTS, 0xff);
++ }
++
++ /* free io regions */
++ sl811_release_regions(hc);
++
++ usb_deregister_bus(hc->bus);
++ usb_free_bus(hc->bus);
++
++ list_del(&hc->hc_hcd_list);
++ INIT_LIST_HEAD(&hc->hc_hcd_list);
++
++ kfree (hc);
++}
++
++/*
++ * This function request IO memory regions, request IRQ, and
++ * allocate all other resources.
++ *
++ * Input: addr_io = first IO address
++ * data_io = second IO address
++ * irq = interrupt number
++ *
++ * Return: 0 = success or error condition
++ */
++static int __devinit sl811_found_hc(int addr_io, int data_io, int irq)
++{
++ struct sl811_hc *hc;
++
++ PDEBUG(4, "enter");
++
++ hc = sl811_alloc_hc();
++ if (!hc)
++ return -ENOMEM;
++
++ if (sl811_request_regions (hc, addr_io, data_io, MODNAME)) {
++ PDEBUG(1, "ioport %X,%X is in use!", addr_io, data_io);
++ sl811_release_hc(hc);
++ return -EBUSY;
++ }
++
++ if (sl811_reg_test(hc)) {
++ PDEBUG(1, "SL811 register test failed!");
++ sl811_release_hc(hc);
++ return -ENODEV;
++ }
++
++//#ifdef SL811_DEBUG_VERBOSE
++ {
++ __u8 u = sl811_read(hc, SL811_HWREV);
++
++ // Show the hardware revision of chip
++ PDEBUG(1, "SL811 HW: %02Xh", u);
++ switch (u & 0xF0) {
++ case 0x00: PDEBUG(1, "SL11H"); break;
++ case 0x10: PDEBUG(1, "SL811HS rev1.2"); break;
++ case 0x20: PDEBUG(1, "SL811HS rev1.5"); break;
++ default: PDEBUG(1, "Revision unknown!");
++ }
++ }
++//#endif // SL811_DEBUG_VERBOSE
++
++ sl811_init_irq();
++
++ usb_register_bus(hc->bus);
++
++ if (request_irq(irq, sl811_interrupt, SA_SHIRQ, MODNAME, hc)) {
++ PDEBUG(1, "request interrupt %d failed", irq);
++ sl811_release_hc(hc);
++ return -EBUSY;
++ }
++ hc->irq = irq;
++
++ printk(KERN_INFO __FILE__ ": USB SL811 at %08x,%08x, IRQ %d\n",
++ hc->addr_io, hc->data_io, irq);
++
++ sl811_hc_reset(hc);
++ sl811_connect_rh(hc);
++
++ return 0;
++}
++
++/*
++ * This is an init function, and it is the first function being called
++ *
++ * Return: 0 = success or error condition
++ */
++static int __init sl811_hcd_init(void)
++{
++ int ret = -ENODEV;
++
++ PDEBUG(4, "enter");
++
++ info(DRIVER_VERSION " : " DRIVER_DESC);
++
++#ifdef CONFIG_X86
++ {
++ int count;
++ // registering some instance
++ for (count = 0; count < MAX_CONTROLERS; count++) {
++ if (io[count]) {
++ ret = sl811_found_hc(io[count], io[count]+OFFSET_DATA_REG, irq[count]);
++ if (ret)
++ return (ret);
++ }
++ }
++ }
++#endif
++#ifdef CONFIG_ARCH_RAMSES
++ ret = sl811_found_hc(0,0,SL811HS_IRQ);
++#endif
++
++ return ret;
++}
++
++/*
++ * This is a cleanup function, and it is called when module is unloaded.
++ */
++static void __exit sl811_hcd_cleanup(void)
++{
++ struct list_head *list = sl811_hcd_list.next;
++ struct sl811_hc *hc;
++
++ PDEBUG(4, "enter");
++
++ for (; list != &sl811_hcd_list; ) {
++ hc = list_entry(list, struct sl811_hc, hc_hcd_list);
++ list = list->next;
++ sl811_release_hc(hc);
++ }
++}
++
++module_init(sl811_hcd_init);
++module_exit(sl811_hcd_cleanup);
++
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
+--- /dev/null
++++ linux-2.4.21/drivers/usb/host/sl811.h
+@@ -0,0 +1,177 @@
++#ifndef __LINUX_SL811_H
++#define __LINUX_SL811_H
++
++#define SL811_DEBUG
++
++#ifdef SL811_DEBUG
++ #define PDEBUG(level, fmt, args...) \
++ if (debug >= (level)) info("[%s:%d] " fmt, \
++ __PRETTY_FUNCTION__, __LINE__ , ## args)
++#else
++ #define PDEBUG(level, fmt, args...) do {} while(0)
++#endif
++
++//#define SL811_TIMEOUT
++
++/* Sl811 host control register */
++#define SL811_CTRL_A 0x00
++#define SL811_ADDR_A 0x01
++#define SL811_LEN_A 0x02
++#define SL811_STS_A 0x03 /* read */
++#define SL811_PIDEP_A 0x03 /* write */
++#define SL811_CNT_A 0x04 /* read */
++#define SL811_DEV_A 0x04 /* write */
++#define SL811_CTRL1 0x05
++#define SL811_INTR 0x06
++#define SL811_CTRL_B 0x08
++#define SL811_ADDR_B 0x09
++#define SL811_LEN_B 0x0A
++#define SL811_STS_B 0x0B /* read */
++#define SL811_PIDEP_B 0x0B /* write */
++#define SL811_CNT_B 0x0C /* read */
++#define SL811_DEV_B 0x0C /* write */
++#define SL811_INTRSTS 0x0D /* write clears bitwise */
++#define SL811_HWREV 0x0E /* read */
++#define SL811_SOFLOW 0x0E /* write */
++#define SL811_SOFCNTDIV 0x0F /* read */
++#define SL811_CTRL2 0x0F /* write */
++
++/* USB control register bits (addr 0x00 and addr 0x08) */
++#define SL811_USB_CTRL_ARM 0x01
++#define SL811_USB_CTRL_ENABLE 0x02
++#define SL811_USB_CTRL_DIR_OUT 0x04
++#define SL811_USB_CTRL_ISO 0x10
++#define SL811_USB_CTRL_SOF 0x20
++#define SL811_USB_CTRL_TOGGLE_1 0x40
++#define SL811_USB_CTRL_PREAMBLE 0x80
++
++/* USB status register bits (addr 0x03 and addr 0x0B) */
++#define SL811_USB_STS_ACK 0x01
++#define SL811_USB_STS_ERROR 0x02
++#define SL811_USB_STS_TIMEOUT 0x04
++#define SL811_USB_STS_TOGGLE_1 0x08
++#define SL811_USB_STS_SETUP 0x10
++#define SL811_USB_STS_OVERFLOW 0x20
++#define SL811_USB_STS_NAK 0x40
++#define SL811_USB_STS_STALL 0x80
++
++/* Control register 1 bits (addr 0x05) */
++#define SL811_CTRL1_SOF 0x01
++#define SL811_CTRL1_RESET 0x08
++#define SL811_CTRL1_JKSTATE 0x10
++#define SL811_CTRL1_SPEED_LOW 0x20
++#define SL811_CTRL1_SUSPEND 0x40
++
++/* Interrut enable (addr 0x06) and interrupt status register bits (addr 0x0D) */
++#define SL811_INTR_DONE_A 0x01
++#define SL811_INTR_DONE_B 0x02
++#define SL811_INTR_SOF 0x10
++#define SL811_INTR_INSRMV 0x20
++#define SL811_INTR_DETECT 0x40
++#define SL811_INTR_NOTPRESENT 0x40
++#define SL811_INTR_SPEED_FULL 0x80 /* only in status reg */
++
++/* HW rev and SOF lo register bits (addr 0x0E) */
++#define SL811_HWR_HWREV 0xF0
++
++/* SOF counter and control reg 2 (addr 0x0F) */
++#define SL811_CTL2_SOFHI 0x3F
++#define SL811_CTL2_DSWAP 0x40
++#define SL811_CTL2_HOST 0x80
++
++/* Set up for 1-ms SOF time. */
++#define SL811_12M_LOW 0xE0
++#define SL811_12M_HI 0x2E
++
++#define SL811_DATA_START 0x10
++#define SL811_DATA_LIMIT 240
++
++
++/* Requests: bRequest << 8 | bmRequestType */
++#define RH_GET_STATUS 0x0080
++#define RH_CLEAR_FEATURE 0x0100
++#define RH_SET_FEATURE 0x0300
++#define RH_SET_ADDRESS 0x0500
++#define RH_GET_DESCRIPTOR 0x0680
++#define RH_SET_DESCRIPTOR 0x0700
++#define RH_GET_CONFIGURATION 0x0880
++#define RH_SET_CONFIGURATION 0x0900
++#define RH_GET_STATE 0x0280
++#define RH_GET_INTERFACE 0x0A80
++#define RH_SET_INTERFACE 0x0B00
++#define RH_SYNC_FRAME 0x0C80
++
++
++#define PIDEP(pid, ep) (((pid) & 0x0f) << 4 | (ep))
++
++/* Virtual Root HUB */
++struct virt_root_hub {
++ int devnum; /* Address of Root Hub endpoint */
++ void *urb; /* interrupt URB of root hub */
++ int send; /* active flag */
++ int interval; /* intervall of roothub interrupt transfers */
++ struct timer_list rh_int_timer; /* intervall timer for rh interrupt EP */
++};
++
++struct sl811_td {
++ /* hardware */
++ __u8 ctrl; /* control register */
++
++ /* write */
++ __u8 addr; /* base adrress register */
++ __u8 len; /* base length register */
++ __u8 pidep; /* PId and endpoint register */
++ __u8 dev; /* device address register */
++
++ /* read */
++ __u8 status; /* status register */
++ __u8 left; /* transfer count register */
++
++ /* software */
++ __u8 errcnt; /* error count, begin with 3 */
++ __u8 done; /* is this td tranfer done */
++ __u8 *buf; /* point to data buffer for tranfer */
++ int bustime; /* the bus time need by this td */
++ int td_status; /* the status of this td */
++ int nakcnt; /* number of naks */
++ struct urb *urb; /* the urb this td belongs to */
++ struct list_head td_list; /* link to a list of the urb */
++};
++
++struct sl811_urb_priv {
++ struct urb *urb; /* the urb this priv beloings to */
++ struct list_head td_list; /* list of all the td of this urb */
++ struct sl811_td *cur_td; /* current td is in processing or it will be */
++ struct sl811_td *first_td; /* the first td of this urb */
++ struct sl811_td *last_td; /* the last td of this urb */
++ int interval; /* the query time value for intr urb */
++ int unlink; /* is the this urb unlinked */
++ unsigned long inserttime; /* the time when insert to list */
++};
++
++struct sl811_hc {
++ spinlock_t hc_lock; /* Lock for this structure */
++
++ int irq; /* IRQ number this hc use */
++ int addr_io; /* I/O address line address */
++ int data_io; /* I/O data line address */
++ struct virt_root_hub rh; /* root hub */
++ struct usb_port_status rh_status;/* root hub port status */
++ struct list_head urb_list[6]; /* set of urbs, the order is iso,intr,ctrl,bulk,inactive intr, wait */
++ struct list_head *cur_list; /* the current list is in process */
++ wait_queue_head_t waitq; /* deletion of URBs and devices needs a waitqueue */
++ struct sl811_td *cur_td; /* point to the td is in process */
++ struct list_head hc_hcd_list; /* list of all hci_hcd */
++ struct usb_bus *bus; /* our bus */
++ int active_urbs; /* total number of active usbs */
++ int frame_number; /* the current frame number, we do't use it, any one need it? */
++};
++
++#define iso_list urb_list[0] /* set of isoc urbs */
++#define intr_list urb_list[1] /* ordered (tree) set of int urbs */
++#define ctrl_list urb_list[2] /* set of ctrl urbs */
++#define bulk_list urb_list[3] /* set of bulk urbs */
++#define idle_intr_list urb_list[4] /* set of intr urbs in its idle time*/
++#define wait_list urb_list[5] /* set of wait urbs */
++
++#endif
+--- linux-2.4.21/drivers/usb/storage/transport.h~usb-sonycamera
++++ linux-2.4.21/drivers/usb/storage/transport.h
+@@ -75,6 +75,8 @@
+ #define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */
+ #endif
+
++#define US_PR_DEVICE 0xff /* Use device's value */
++
+ /*
+ * Bulk only data structures
+ */
+--- linux-2.4.21/drivers/usb/storage/unusual_devs.h~usb-sonycamera
++++ linux-2.4.21/drivers/usb/storage/unusual_devs.h
+@@ -223,10 +223,10 @@
+ US_FL_FIX_INQUIRY | US_FL_START_STOP ),
+
+ /* This entry is needed because the device reports Sub=ff */
+-UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0440,
++UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450,
+ "Sony",
+- "DSC-S30/S70/S75/505V/F505/F707/F717",
+- US_SC_SCSI, US_PR_CB, NULL,
++ "DSC-S30/S70/S75/505V/F505/F707/F717/P8",
++ US_SC_SCSI, US_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ),
+
+ /* Reported by wim@geeks.nl */
+--- linux-2.4.21/drivers/usb/storage/usb.c~usb-sonycamera
++++ linux-2.4.21/drivers/usb/storage/usb.c
+@@ -622,7 +622,9 @@
+
+ /* Determine subclass and protocol, or copy from the interface */
+ subclass = unusual_dev->useProtocol;
+- protocol = unusual_dev->useTransport;
++ protocol = (unusual_dev->useTransport == US_PR_DEVICE) ?
++ altsetting->bInterfaceProtocol :
++ unusual_dev->useTransport;
+ flags = unusual_dev->flags;
+
+ /*
+--- linux-2.4.21/drivers/video/fbcon-cfb16.c~fb-turn180
++++ linux-2.4.21/drivers/video/fbcon-cfb16.c
+@@ -34,6 +34,41 @@
+ #endif
+ };
+
++static u8 mirrortab_cfb16[] = {
++ 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,
++ 0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
++ 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,
++ 0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
++ 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,
++ 0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
++ 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,
++ 0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
++ 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,
++ 0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
++ 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,
++ 0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
++ 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,
++ 0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
++ 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,
++ 0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
++ 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,
++ 0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
++ 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,
++ 0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
++ 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,
++ 0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
++ 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,
++ 0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
++ 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,
++ 0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
++ 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,
++ 0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
++ 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,
++ 0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
++ 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,
++ 0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
++};
++
+ void fbcon_cfb16_setup(struct display *p)
+ {
+ p->next_line = p->line_length ? p->line_length : p->var.xres_virtual<<1;
+@@ -46,6 +81,53 @@
+ int bytes = p->next_line, linesize = bytes * fontheight(p), rows;
+ u8 *src, *dst;
+
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ char *scrn_end = p->screen_base + p->var.xres*p->var.yres * 2;
++/*
++ printk("---@paul@-------------------------\n"\
++ "fbcon_cfb16_bmove() %d %d %d %d %d %d\n",
++ sx,sy,dx,dy,height,width
++ );
++*/
++ if (sx == 0 && dx == 0 && width * fontwidth(p) * 2 == bytes)
++ {
++ fb_memmove(
++ scrn_end - dy * linesize,
++ scrn_end - sy * linesize,
++ height * linesize
++ );
++ return;
++ }
++ if (fontwidthlog(p)) {
++ sx <<= fontwidthlog(p)+1;
++ dx <<= fontwidthlog(p)+1;
++ width <<= fontwidthlog(p)+1;
++ } else {
++ sx *= fontwidth(p)*2;
++ dx *= fontwidth(p)*2;
++ width *= fontwidth(p)*2;
++ }
++ if (dy < sy || (dy == sy && dx < sx)) {
++ src = scrn_end + sy * linesize + sx;
++ dst = scrn_end + dy * linesize + dx;
++ for (rows = height * fontheight(p); rows--;)
++ {
++ fb_memmove(dst, src, width);
++ src += bytes;
++ dst += bytes;
++ }
++ } else {
++ src = scrn_end + (sy+height) * linesize + sx - bytes;
++ dst = scrn_end + (dy+height) * linesize + dx - bytes;
++ for (rows = height * fontheight(p); rows--;)
++ {
++ fb_memmove(dst, src, width);
++ src -= bytes;
++ dst -= bytes;
++ }
++ }
++/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
++ } else {
+ if (sx == 0 && dx == 0 && width * fontwidth(p) * 2 == bytes) {
+ fb_memmove(p->screen_base + dy * linesize,
+ p->screen_base + sy * linesize,
+@@ -78,6 +160,8 @@
+ dst -= bytes;
+ }
+ }
++ }
++/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
+ }
+
+ static inline void rectfill(u8 *dest, int width, int height, u32 data,
+@@ -108,10 +192,16 @@
+ int bytes = p->next_line, lines = height * fontheight(p);
+ u32 bgx;
+
+- dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 2;
+-
+- bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+-
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dest = p->screen_base
++ + p->var.xres*p->var.yres * 2
++ - (sy+height) * fontheight(p) * bytes
++ + sx * fontwidth(p) * 2;
++ bgx = 1;
++ } else {
++ dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 2;
++ bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
++ }
+ width *= fontwidth(p)/4;
+ if (width * 8 == bytes)
+ rectfill(dest, lines * width * 4, 1, bgx, bytes);
+@@ -126,14 +216,69 @@
+ int bytes = p->next_line, rows;
+ u32 eorx, fgx, bgx;
+
+- dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
+-
+ fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
+ bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
+ fgx |= (fgx << 16);
+ bgx |= (bgx << 16);
+ eorx = fgx ^ bgx;
+
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dest = p->screen_base
++ + p->var.xres*p->var.yres * 2
++ - yy * fontheight(p) * bytes
++ - xx * fontwidth(p) * 2;
++
++ switch (fontwidth(p)) {
++ case 4:
++ cdat = p->fontdata + (c & p->charmask) * fontheight(p);
++ for (rows = fontheight(p); rows--; dest += bytes)
++ {
++ bits = mirrortab_cfb16[*cdat++];
++ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-8);
++ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-4);
++ }
++ case 8:
++ cdat = p->fontdata + (c & p->charmask) * fontheight(p);
++ for (rows = fontheight(p); rows--; dest += bytes)
++ {
++ bits = mirrortab_cfb16[*cdat++];
++ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-16);
++ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-12);
++ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-8);
++ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-4);
++ }
++ break;
++ case 12:
++ cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1);
++ for (rows = fontheight(p); rows--; dest += bytes) {
++ bits = mirrortab_cfb16[*cdat++];
++ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-24);
++ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-20);
++ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-16);
++ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-12);
++ bits = mirrortab_cfb16[*cdat++];
++ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-8);
++ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-4);
++ }
++ case 16:
++ cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1);
++ for (rows = fontheight(p); rows--; dest += bytes) {
++ bits = mirrortab_cfb16[*cdat++];
++ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-32);
++ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-28);
++ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-24);
++ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-20);
++ bits = mirrortab_cfb16[*cdat++];
++ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-16);
++ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-12);
++ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-8);
++ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-4);
++ }
++ break;
++ }
++/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
++ } else {
++ dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
+ switch (fontwidth(p)) {
+ case 4:
+ case 8:
+@@ -167,6 +312,8 @@
+ }
+ break;
+ }
++ }
++/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
+ }
+
+ void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
+@@ -177,7 +324,6 @@
+ int rows, bytes = p->next_line;
+ u32 eorx, fgx, bgx;
+
+- dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
+ c = scr_readw(s);
+ fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
+ bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
+@@ -185,6 +331,81 @@
+ bgx |= (bgx << 16);
+ eorx = fgx ^ bgx;
+
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dest0 = p->screen_base
++ + p->var.xres * p->var.yres * 2
++ - yy * fontheight(p) * bytes
++ - xx * fontwidth(p) * 2;
++
++ switch (fontwidth(p)) {
++ case 4:
++ while (count--) {
++ c = scr_readw(s++) & p->charmask;
++ cdat = p->fontdata + c * fontheight(p);
++ for (rows = fontheight(p), dest = dest0; rows--; dest -= bytes)
++ {
++ u8 bits = mirrortab_cfb16[*cdat++];
++ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-8);
++ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-4);
++ }
++ dest0 -= fontwidth(p)*2;
++ }
++ case 8:
++ while (count--) {
++ c = scr_readw(s++) & p->charmask;
++ cdat = p->fontdata + c * fontheight(p);
++ for (rows = fontheight(p), dest = dest0; rows--; dest -= bytes)
++ {
++ u8 bits = mirrortab_cfb16[*cdat++];
++ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-16);
++ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-12);
++ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-8);
++ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-4);
++ }
++ dest0 -= fontwidth(p)*2;
++ }
++ break;
++ case 12:
++ while (count--) {
++ c = scr_readw(s++) & p->charmask;
++ cdat = p->fontdata + (c * fontheight(p) << 1);
++ for (rows = fontheight(p), dest = dest0; rows--; dest -= bytes)
++ {
++ u8 bits = mirrortab_cfb16[*cdat++];
++ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-24);
++ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-20);
++ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-16);
++ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-12);
++ bits = mirrortab_cfb16[*cdat++];
++ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-8);
++ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-4);
++ }
++ dest0 -= fontwidth(p)*2;
++ }
++ case 16:
++ while (count--) {
++ c = scr_readw(s++) & p->charmask;
++ cdat = p->fontdata + (c * fontheight(p) << 1);
++ for (rows = fontheight(p), dest = dest0; rows--; dest -= bytes)
++ {
++ u8 bits = mirrortab_cfb16[*cdat++];
++ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-32);
++ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-28);
++ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-24);
++ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-20);
++ bits = mirrortab_cfb16[*cdat++];
++ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-16);
++ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-12);
++ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-8);
++ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-4);
++ }
++ dest0 -= fontwidth(p)*2;
++ }
++ break;
++ }
++/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
++ } else {
++ dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2;
+ switch (fontwidth(p)) {
+ case 4:
+ case 8:
+@@ -226,6 +447,8 @@
+ }
+ break;
+ }
++ }
++/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
+ }
+
+ void fbcon_cfb16_revc(struct display *p, int xx, int yy)
+@@ -233,6 +456,32 @@
+ u8 *dest;
+ int bytes = p->next_line, rows;
+
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dest = p->screen_base
++ + p->var.xres*p->var.yres * 2
++ - yy * fontheight(p) * bytes
++ - xx * fontwidth(p) * 2;
++ for (rows = fontheight(p); rows--; dest -= bytes) {
++ switch (fontwidth(p)) {
++ case 16:
++ fb_writel(fb_readl(dest-32) ^ 0xffffffff, dest-32);
++ fb_writel(fb_readl(dest-28) ^ 0xffffffff, dest-28);
++ /* FALL THROUGH */
++ case 12:
++ fb_writel(fb_readl(dest-24) ^ 0xffffffff, dest-24);
++ fb_writel(fb_readl(dest-20) ^ 0xffffffff, dest-20);
++ /* FALL THROUGH */
++ case 8:
++ fb_writel(fb_readl(dest-16) ^ 0xffffffff, dest-16);
++ fb_writel(fb_readl(dest-12) ^ 0xffffffff, dest-12);
++ /* FALL THROUGH */
++ case 4:
++ fb_writel(fb_readl(dest-8) ^ 0xffffffff, dest-8);
++ fb_writel(fb_readl(dest-4) ^ 0xffffffff, dest-4);
++ }
++ }
++/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
++ } else {
+ dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p)*2;
+ for (rows = fontheight(p); rows--; dest += bytes) {
+ switch (fontwidth(p)) {
+@@ -253,6 +502,8 @@
+ fb_writel(fb_readl(dest+4) ^ 0xffffffff, dest+4);
+ }
+ }
++ }
++/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
+ }
+
+ void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p,
+@@ -268,6 +519,9 @@
+ bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+
+ if (!bottom_only && (right_width = p->var.xres-right_start))
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ printk("---@paul@------------------------- fbcon-cfb16 clear margins\n");
++ }
+ rectfill(p->screen_base+right_start*2, right_width,
+ p->var.yres_virtual, bgx, bytes);
+ if ((bottom_width = p->var.yres-bottom_start))
+--- linux-2.4.21/drivers/video/fbcon-cfb8.c~fb-turn180
++++ linux-2.4.21/drivers/video/fbcon-cfb8.c
+@@ -39,6 +39,41 @@
+ #endif
+ };
+
++static u8 mirrortab_cfb8[] = {
++ 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,
++ 0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
++ 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,
++ 0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
++ 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,
++ 0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
++ 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,
++ 0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
++ 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,
++ 0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
++ 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,
++ 0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
++ 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,
++ 0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
++ 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,
++ 0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
++ 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,
++ 0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
++ 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,
++ 0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
++ 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,
++ 0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
++ 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,
++ 0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
++ 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,
++ 0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
++ 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,
++ 0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
++ 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,
++ 0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
++ 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,
++ 0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
++};
++
+ void fbcon_cfb8_setup(struct display *p)
+ {
+ p->next_line = p->line_length ? p->line_length : p->var.xres_virtual;
+@@ -51,10 +86,57 @@
+ int bytes = p->next_line, linesize = bytes * fontheight(p), rows;
+ u8 *src,*dst;
+
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++/*
++ printk("---@paul@-------------------------\n"\
++ "fbcon_cfb8_bmove() %d %d %d %d %d %d\n",
++ sx,sy,dx,dy,height,width
++ );
++*/
++ if (sx == 0 && dx == 0 && width * fontwidth(p) == bytes)
++ {
++ fb_memmove(
++ p->screen_base + p->var.xres*p->var.yres - dy * linesize,
++ p->screen_base + p->var.xres*p->var.yres - sy * linesize,
++ height * linesize);
++ return;
++ }
++ if (fontwidthlog(p)) {
++ sx <<= fontwidthlog(p); dx <<= fontwidthlog(p); width <<= fontwidthlog(p);
++ } else {
++ sx *= fontwidth(p); dx *= fontwidth(p); width *= fontwidth(p);
++ }
++ if (dy < sy || (dy == sy && dx < sx))
++ {
++ src = p->screen_base + p->var.xres*p->var.yres
++ - sy * linesize - sx;
++ dst = p->screen_base + p->var.xres*p->var.yres
++ - dy * linesize - dx;
++ for (rows = height * fontheight(p) ; rows-- ;)
++ {
++ fb_memmove(dst, src, width);
++ src += bytes;
++ dst += bytes;
++ }
++ } else
++ {
++ src = p->screen_base + p->var.xres*p->var.yres
++ - (sy+height) * linesize - sx + bytes;
++ dst = p->screen_base + p->var.xres*p->var.yres
++ - (dy+height) * linesize - dx + bytes;
++ for (rows = height * fontheight(p) ; rows-- ;)
++ {
++ fb_memmove(dst, src, width);
++ src -= bytes;
++ dst -= bytes;
++ }
++ }
++/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
++ } else {
+ if (sx == 0 && dx == 0 && width * fontwidth(p) == bytes) {
+- fb_memmove(p->screen_base + dy * linesize,
+- p->screen_base + sy * linesize,
+- height * linesize);
++ fb_memmove(p->screen_base + dy * linesize,
++ p->screen_base + sy * linesize,
++ height * linesize);
+ return;
+ }
+ if (fontwidthlog(p)) {
+@@ -79,6 +161,7 @@
+ dst -= bytes;
+ }
+ }
++/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
+ }
+
+ static inline void rectfill(u8 *dest, int width, int height, u8 data,
+@@ -97,11 +180,17 @@
+ int bytes=p->next_line,lines=height * fontheight(p);
+ u8 bgx;
+
+- dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p);
+-
+- bgx=attr_bgcol_ec(p,conp);
+-
+- width *= fontwidth(p);
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ bgx=attr_bgcol_ec(p,conp);
++ width *= fontwidth(p);
++ dest = p->screen_base + p->var.xres*p->var.yres
++ - (sy+height) * fontheight(p) * bytes
++ + sx * fontwidth(p);
++ } else {
++ dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p);
++ bgx=attr_bgcol_ec(p,conp);
++ width *= fontwidth(p);
++ }
+ if (width == bytes)
+ rectfill(dest, lines * width, 1, bgx, bytes);
+ else
+@@ -114,8 +203,8 @@
+ u8 *dest,*cdat;
+ int bytes=p->next_line,rows;
+ u32 eorx,fgx,bgx;
++ u8 chrrow;
+
+- dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
+ if (fontwidth(p) <= 8)
+ cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+ else
+@@ -129,6 +218,53 @@
+ bgx |= (bgx << 16);
+ eorx = fgx ^ bgx;
+
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dest = p->screen_base
++ + p->var.xres*p->var.yres
++ - yy * fontheight(p) * bytes
++ - xx * fontwidth(p);
++
++ switch (fontwidth(p)) {
++ case 4:
++ for (rows = fontheight(p) ; rows-- ; dest += bytes)
++ {
++ chrrow = mirrortab_cfb8[*cdat++];
++ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-4);
++ }
++ break;
++ case 8:
++ for (rows = fontheight(p) ; rows-- ; dest += bytes)
++ {
++ chrrow = mirrortab_cfb8[*cdat++];
++ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-8);
++ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-4);
++ }
++ break;
++ case 12:
++ for (rows = fontheight(p) ; rows-- ; dest += bytes)
++ {
++ chrrow = mirrortab_cfb8[*cdat++];
++ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-12);
++ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-8);
++ chrrow = mirrortab_cfb8[*cdat++];
++ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-4);
++ }
++ break;
++ case 16:
++ for (rows = fontheight(p) ; rows-- ; dest += bytes)
++ {
++ chrrow = mirrortab_cfb8[*cdat++];
++ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-16);
++ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-12);
++ chrrow = mirrortab_cfb8[*cdat++];
++ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-8);
++ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-4);
++ }
++ break;
++ }
++/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
++ } else {
++ dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
+ switch (fontwidth(p)) {
+ case 4:
+ for (rows = fontheight(p) ; rows-- ; dest += bytes)
+@@ -152,6 +288,8 @@
+ }
+ break;
+ }
++ }
++/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
+ }
+
+ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
+@@ -161,8 +299,8 @@
+ u16 c;
+ int rows,bytes=p->next_line;
+ u32 eorx, fgx, bgx;
++ u8 chrrow;
+
+- dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
+ c = scr_readw(s);
+ fgx = attr_fgcol(p, c);
+ bgx = attr_bgcol(p, c);
+@@ -171,6 +309,76 @@
+ bgx |= (bgx << 8);
+ bgx |= (bgx << 16);
+ eorx = fgx ^ bgx;
++
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dest0 = p->screen_base
++ + p->var.xres*p->var.yres
++ - yy * fontheight(p) * bytes
++ - xx * fontwidth(p);
++ switch (fontwidth(p)) {
++ case 4:
++ while (count--) {
++ c = scr_readw(s++) & p->charmask;
++ cdat = p->fontdata + c * fontheight(p);
++
++ for (rows = fontheight(p), dest = dest0; rows-- ; dest -= bytes)
++ {
++ chrrow = mirrortab_cfb8[*cdat++];
++ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-4);
++ }
++ dest0 -= 4;
++ }
++ break;
++ case 8:
++ while (count--) {
++ c = scr_readw(s++) & p->charmask;
++ cdat = p->fontdata + c * fontheight(p);
++ for (rows = fontheight(p), dest = dest0; rows-- ; dest -= bytes)
++ {
++ chrrow = mirrortab_cfb8[*cdat++];
++ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-8);
++ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-4);
++ }
++ dest0 -= 8;
++ }
++ break;
++ case 12:
++ while (count--) {
++ c = scr_readw(s++) & p->charmask;
++ cdat = p->fontdata + (c * fontheight(p) << 1);
++
++ for (rows = fontheight(p), dest = dest0; rows-- ; dest -= bytes)
++ {
++ chrrow = mirrortab_cfb8[*cdat++];
++ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-12);
++ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-8);
++ chrrow = mirrortab_cfb8[*cdat++];
++ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-4);
++ }
++ dest0 -= fontwidth(p);
++ }
++ break;
++ case 16:
++ while (count--) {
++ c = scr_readw(s++) & p->charmask;
++ cdat = p->fontdata + (c * fontheight(p) << 1);
++
++ for (rows = fontheight(p), dest = dest0; rows-- ; dest -= bytes)
++ {
++ chrrow = mirrortab_cfb8[*cdat++];
++ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-16);
++ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-12);
++ chrrow = mirrortab_cfb8[*cdat++];
++ fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-8);
++ fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-4);
++ }
++ dest0 -= fontwidth(p);
++ }
++ break;
++ } /* switch (fontwidth(p)) */
++/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
++ } else {
++ dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
+ switch (fontwidth(p)) {
+ case 4:
+ while (count--) {
+@@ -212,6 +420,8 @@
+ }
+ break;
+ }
++ }
++/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
+ }
+
+ void fbcon_cfb8_revc(struct display *p, int xx, int yy)
+@@ -219,6 +429,21 @@
+ u8 *dest;
+ int bytes=p->next_line, rows;
+
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dest = p->screen_base + p->var.xres*p->var.yres
++ - yy * fontheight(p) * bytes
++ - xx * fontwidth(p);
++ for (rows = fontheight(p) ; rows-- ; dest -= bytes) {
++ switch (fontwidth(p)) {
++ case 16: fb_writel(fb_readl(dest-16) ^ 0x0f0f0f0f, dest-16); /* fall thru */
++ case 12: fb_writel(fb_readl(dest-12) ^ 0x0f0f0f0f, dest-12); /* fall thru */
++ case 8: fb_writel(fb_readl(dest-8) ^ 0x0f0f0f0f, dest-8); /* fall thru */
++ case 4: fb_writel(fb_readl(dest-4) ^ 0x0f0f0f0f, dest-4); /* fall thru */
++ default: break;
++ }
++ }
++/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
++ } else {
+ dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
+ for (rows = fontheight(p) ; rows-- ; dest += bytes) {
+ switch (fontwidth(p)) {
+@@ -229,6 +454,8 @@
+ default: break;
+ }
+ }
++ }
++/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */
+ }
+
+ void fbcon_cfb8_clear_margins(struct vc_data *conp, struct display *p,
+@@ -244,6 +471,9 @@
+ bgx=attr_bgcol_ec(p,conp);
+
+ if (!bottom_only && (right_width = p->var.xres-right_start))
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ printk("---@paul@------------------------- fbcon-cfb8 clear margins\n");
++ }
+ rectfill(p->screen_base+right_start, right_width, p->var.yres_virtual,
+ bgx, bytes);
+ if ((bottom_width = p->var.yres-bottom_start))
+--- linux-2.4.21/drivers/video/fbcon.c~fb-turn180
++++ linux-2.4.21/drivers/video/fbcon.c
+@@ -1558,6 +1558,7 @@
+ update_region(fg_console,
+ conp->vc_origin + conp->vc_size_row * conp->vc_top,
+ conp->vc_size_row * (conp->vc_bottom - conp->vc_top) / 2);
++ conp->vc_top = 0;
+ return 0;
+ }
+ return 1;
+@@ -2209,7 +2210,16 @@
+ src = logo;
+ bdepth = depth/8;
+ for( y1 = 0; y1 < LOGO_H; y1++ ) {
+- dst = fb + y1*line + x*bdepth;
++
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++/*
++ Das ist NICHT die richtige Stelle für den Ramses 16 BPP Modus
++ aber dafür die weiter unten.
++*/
++ dst = fb + p->var.xres*p->var.yres*bdepth -1 - y1*line - x*bdepth;
++ } else {
++ dst = fb + y1*line + x*bdepth;
++ }
+ for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
+ val = (*src << redshift) |
+ (*src << greenshift) |
+@@ -2217,18 +2227,32 @@
+ if (bdepth == 4 && !((long)dst & 3)) {
+ /* Some cards require 32bit access */
+ fb_writel (val, dst);
+- dst += 4;
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dst -= 4;
++ } else {
++ dst += 4;
++ }
+ } else if (bdepth == 2 && !((long)dst & 1)) {
+ /* others require 16bit access */
+ fb_writew (val,dst);
+- dst +=2;
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dst -= 2;
++ } else {
++ dst +=2;
++ }
+ } else {
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ for( i = bdepth-1; i >= 0; --i )
++ fb_writeb (val >> (i*8), dst--);
++
++ } else {
+ #ifdef __LITTLE_ENDIAN
+- for( i = 0; i < bdepth; ++i )
++ for( i = 0; i < bdepth; ++i )
+ #else
+- for( i = bdepth-1; i >= 0; --i )
++ for( i = bdepth-1; i >= 0; --i )
+ #endif
+- fb_writeb (val >> (i*8), dst++);
++ fb_writeb (val >> (i*8), dst++);
++ }
+ }
+ }
+ }
+@@ -2239,28 +2263,42 @@
+ src = linux_logo16;
+ bdepth = (depth+7)/8;
+ for( y1 = 0; y1 < LOGO_H; y1++ ) {
+- dst = fb + y1*line + x*bdepth;
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dst = fb + p->var.xres*p->var.yres*bdepth -1 - y1*line - x*bdepth;
++ } else {
++ dst = fb + y1*line + x*bdepth;
++ }
+ for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) {
+ pix = *src >> 4; /* upper nibble */
+ val = (pix << redshift) |
+ (pix << greenshift) |
+ (pix << blueshift);
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ for( i = bdepth-1; i >= 0; --i )
++ fb_writeb (val >> (i*8), dst--);
++ } else {
+ #ifdef __LITTLE_ENDIAN
+- for( i = 0; i < bdepth; ++i )
++ for( i = 0; i < bdepth; ++i )
+ #else
+- for( i = bdepth-1; i >= 0; --i )
++ for( i = bdepth-1; i >= 0; --i )
+ #endif
+- fb_writeb (val >> (i*8), dst++);
++ fb_writeb (val >> (i*8), dst++);
++ }
+ pix = *src & 0x0f; /* lower nibble */
+ val = (pix << redshift) |
+ (pix << greenshift) |
+ (pix << blueshift);
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ for( i = bdepth-1; i >= 0; --i )
++ fb_writeb (val >> (i*8), dst--);
++ } else {
+ #ifdef __LITTLE_ENDIAN
+- for( i = 0; i < bdepth; ++i )
++ for( i = 0; i < bdepth; ++i )
+ #else
+- for( i = bdepth-1; i >= 0; --i )
++ for( i = bdepth-1; i >= 0; --i )
+ #endif
+- fb_writeb (val >> (i*8), dst++);
++ fb_writeb (val >> (i*8), dst++);
++ }
+ }
+ }
+ }
+@@ -2287,7 +2325,11 @@
+
+ src = logo;
+ for( y1 = 0; y1 < LOGO_H; y1++ ) {
+- dst = fb + y1*line + x*bdepth;
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dst = fb + p->var.xres*p->var.yres*bdepth -1 - y1*line - x*bdepth;
++ } else {
++ dst = fb + y1*line + x*bdepth;
++ }
+ for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
+ val = safe_shift((linux_logo_red[*src-32] & redmask), redshift) |
+ safe_shift((linux_logo_green[*src-32] & greenmask), greenshift) |
+@@ -2295,18 +2337,31 @@
+ if (bdepth == 4 && !((long)dst & 3)) {
+ /* Some cards require 32bit access */
+ fb_writel (val, dst);
+- dst += 4;
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dst -= 4;
++ } else {
++ dst += 4;
++ }
+ } else if (bdepth == 2 && !((long)dst & 1)) {
+ /* others require 16bit access */
+ fb_writew (val,dst);
+- dst +=2;
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ dst -= 2;
++ } else {
++ dst +=2;
++ }
+ } else {
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ for( i = bdepth-1; i >= 0; --i )
++ fb_writeb (val >> (i*8), dst--);
++ } else {
+ #ifdef __LITTLE_ENDIAN
+- for( i = 0; i < bdepth; ++i )
++ for( i = 0; i < bdepth; ++i )
+ #else
+- for( i = bdepth-1; i >= 0; --i )
++ for( i = bdepth-1; i >= 0; --i )
+ #endif
+- fb_writeb (val >> (i*8), dst++);
++ fb_writeb (val >> (i*8), dst++);
++ }
+ }
+ }
+ }
+@@ -2331,13 +2386,24 @@
+ if (depth == 8 && p->type == FB_TYPE_PACKED_PIXELS) {
+ /* depth 8 or more, packed, with color registers */
+
+- src = logo;
+- for( y1 = 0; y1 < LOGO_H; y1++ ) {
+- dst = fb + y1*line + x;
+- for( x1 = 0; x1 < LOGO_W; x1++ )
+- fb_writeb (*src++, dst++);
+- }
+- done = 1;
++ if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) {
++ src = logo;
++ for( y1 = 0; y1 < LOGO_H; y1++ )
++ {
++ dst = fb + p->var.xres*p->var.yres -1 - y1*line - x;
++ for( x1 = 0; x1 < LOGO_W; x1++ )
++ fb_writeb (*src++, dst--);
++ }
++ done = 1;
++ } else {
++ src = logo;
++ for( y1 = 0; y1 < LOGO_H; y1++ ) {
++ dst = fb + y1*line + x;
++ for( x1 = 0; x1 < LOGO_W; x1++ )
++ fb_writeb (*src++, dst++);
++ }
++ done = 1;
++ }
+ }
+ #endif
+ #if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_ILBM) || \
+--- linux-2.4.21/drivers/video/fbmem.c~fb-buffered
++++ linux-2.4.21/drivers/video/fbmem.c
+@@ -302,7 +302,7 @@
+ { "sa1100", sa1100fb_init, NULL },
+ #endif
+ #ifdef CONFIG_FB_PXA
+- { "pxa", pxafb_init, NULL },
++ { "pxa", pxafb_init, NULL },
+ #endif
+ #ifdef CONFIG_FB_SUN3
+ { "sun3", sun3fb_init, sun3fb_setup },
+@@ -672,7 +672,11 @@
+ #elif defined(__hppa__)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+ #elif defined(__ia64__) || defined(__arm__)
++#ifdef CONFIG_PXA
++ vma->vm_page_prot = pgprot_noncached_buffered(vma->vm_page_prot);
++#else
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
++#endif
+ #elif defined(__hppa__)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+ #else
+--- linux-2.4.21/drivers/video/pxafb.c~ramses-lcd
++++ linux-2.4.21/drivers/video/pxafb.c
+@@ -45,8 +45,6 @@
+
+ #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 */
+
+@@ -57,7 +55,7 @@
+ /*
+ * Complain if VAR is out of range.
+ */
+-#define DEBUG_VAR 1
++#define DEBUG_VAR 0
+
+ #undef ASSABET_PAL_VIDEO
+
+@@ -66,16 +64,6 @@
+ 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, },
+@@ -99,9 +87,30 @@
+ lccr3: LCD_LCCR3
+ };
+
++static struct pxafb_mach_info torisan_fb_info __initdata = {
++ pixclock: 70000,
++ bpp: LCD_BPP,
++ xres: 320,
++ yres: 240,
++ hsync_len: 2,
++ vsync_len: 2,
++ left_margin: 1,
++ upper_margin: 4,
++ right_margin: 139,
++ lower_margin: 4,
++ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ lccr0: LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_QDM | LCCR0_BM | LCCR0_OUM | LCCR0_PAS,
++ lccr3: 0x04700007
++};
++
+ static struct pxafb_mach_info * __init
+ pxafb_get_machine_info(struct pxafb_info *fbi)
+ {
++#ifdef CONFIG_ARCH_RAMSES
++ if (ramses_lcd_type == 2)
++ return &torisan_fb_info;
++ else
++#endif
+ return &pxa_fb_info;
+ }
+
+@@ -276,7 +285,7 @@
+ * 16 bits works apparemtly fine in passive mode for those,
+ * so don't complain
+ */
+- if (machine_is_lubbock() ||
++ if (machine_is_lubbock() || machine_is_ramses() ||
+ machine_is_pxa_cerf()) {
+ ret = 0;
+ } else
+@@ -671,7 +680,7 @@
+ 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_int pcd = get_pcd(var->pixclock);
+ u_long flags;
+
+ DPRINTK("Configuring PXA LCD\n");
+@@ -710,7 +719,7 @@
+ fbi->fb.fix.id, var->lower_margin);
+ #endif
+
+-#if defined (CONFIG_PXA_CERF_PDA)
++#if defined (CONFIG_PXA_CERF_PDA) || defined(CONFIG_ARCH_RAMSES)
+ new_regs.lccr0 = fbi->lccr0;
+ new_regs.lccr1 =
+ LCCR1_DisWdth(var->xres) +
+@@ -767,8 +776,8 @@
+ // LCCR3_ACBsCntOff;
+ #endif
+
+-// if (pcd)
+-// new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
++ if (pcd)
++ new_regs.lccr3 = (new_regs.lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
+
+ DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
+ DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
+@@ -820,6 +829,7 @@
+ fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
+ }
+
++#if 0
+ 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);
+@@ -838,6 +848,7 @@
+ 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);
++#endif
+
+ fbi->reg_lccr0 = new_regs.lccr0;
+ fbi->reg_lccr1 = new_regs.lccr1;
+@@ -874,14 +885,20 @@
+ DPRINTK("backlight on\n");
+
+ #ifdef CONFIG_ARCH_PXA_IDP
+- if(machine_is_pxa_idp()) {
++ if (machine_is_pxa_idp()) {
+ FB_BACKLIGHT_ON();
+ }
+ #endif
++#ifdef CONFIG_ARCH_RAMSES
++ if (machine_is_ramses()) {
++//printk("--> pxafb_backlight_on\n");
++ ramses_lcd_backlight_on();
++ }
++#endif
+ }
+
+ /*
+- * FIXME: move LCD power stuf into pxafb_power_down_lcd()
++ * FIXME: move LCD power stuff into pxafb_power_down_lcd()
+ * Also, I'm expecting that the backlight stuff should
+ * be handled differently.
+ */
+@@ -894,7 +911,13 @@
+ FB_BACKLIGHT_OFF();
+ }
+ #endif
+-
++
++#ifdef CONFIG_ARCH_RAMSES
++ if (machine_is_ramses()) {
++//printk("--> pxafb_backlight_off calling ramses_lcd_backlight_off\n");
++ ramses_lcd_backlight_off();
++ }
++#endif
+ }
+
+ static void pxafb_power_up_lcd(struct pxafb_info *fbi)
+@@ -902,11 +925,10 @@
+ DPRINTK("LCD power on\n");
+ CKEN |= CKEN16_LCD;
+
+- if(machine_is_pxa_cerf()) {
++ if (machine_is_pxa_cerf()) {
+ lcdctrl_enable();
+ }
+-
+-#if CONFIG_ARCH_PXA_IDP
++#ifdef CONFIG_ARCH_PXA_IDP
+ /* set GPIOs, etc */
+ if(machine_is_pxa_idp()) {
+ // FIXME need to add proper delays
+@@ -914,26 +936,36 @@
+ FB_VLCD_ON(); // FIXME this should be after scanning starts
+ }
+ #endif
++
++#ifdef CONFIG_ARCH_RAMSES
++ if (machine_is_ramses()) {
++//printk("--> pxafb_power_up_lcd\n");
++ ramses_lcd_power_on();
++ }
++#endif
+ }
+
+ static void pxafb_power_down_lcd(struct pxafb_info *fbi)
+ {
+ DPRINTK("LCD power off\n");
++#ifdef CONFIG_ARCH_RAMSES
++ if (machine_is_ramses()) {
++//printk("--> pxafb_power_down_lcd calling ramses_lcd_power_off\n");
++ ramses_lcd_power_off();
++ }
++#endif
+ CKEN &= ~CKEN16_LCD;
+
+- if(machine_is_pxa_cerf()) {
++ if (machine_is_pxa_cerf()) {
+ lcdctrl_disable();
+ }
+-
+- /* set GPIOs, etc */
+-#if CONFIG_ARCH_PXA_IDP
++#ifdef 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)
+@@ -1082,6 +1114,10 @@
+ if (old_state != C_DISABLE) {
+ fbi->state = state;
+
++#ifdef CONFIG_ARCH_PXA
++ //printk("--> set_ctrlr_state(%d) calling ramses_lcd_power_off\n", state);
++ ramses_lcd_power_off();
++#endif
+ pxafb_backlight_off(fbi);
+ if (old_state != C_DISABLE_CLKCHANGE)
+ pxafb_disable_controller(fbi);
+@@ -1191,6 +1227,7 @@
+
+ if (state == 0) {
+ /* Enter D0. */
++//printk("--> pxafb_pm_callback(%d)\n", req);
+ set_ctrlr_state(fbi, C_ENABLE);
+ } else {
+ /* Enter D1-D3. Disable the LCD controller. */
+@@ -1300,7 +1337,6 @@
+ 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);
+@@ -1348,11 +1384,18 @@
+ if (!fbi)
+ goto failed;
+
+- if(machine_is_pxa_cerf()) {
+- // brightness&contrast is handled via lcdctrl.
++ if (machine_is_pxa_cerf()) {
++ // brightness & contrast is handled via lcdctrl
+ lcdctrl_init();
+ }
+-
++#if 0
++ ifdef CONFIG_ARCH_RAMSES
++ if (machine_is_ramses()) {
++ ramses_lcd_set_intensity(100);
++ ramses_lcd_set_brightness(20);
++ ramses_lcd_set_contrast(84,1);
++ }
++#endif
+ /* Initialize video memory */
+ ret = pxafb_map_video_memory(fbi);
+ if (ret)
+--- linux-2.4.21/drivers/video/pxafb.h~ramses-lcd
++++ linux-2.4.21/drivers/video/pxafb.h
+@@ -235,4 +235,22 @@
+ #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))
+
++#elif defined CONFIG_ARCH_RAMSES
++#define LCD_PIXCLOCK 100000
++#define LCD_BPP PXAFB_BPP
++#define LCD_XRES 240
++#define LCD_YRES 320
++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 6
++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 1
++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 21
++#define LCD_BEGIN_FRAME_WAIT_COUNT 7
++#define LCD_END_OF_LINE_WAIT_COUNT 21
++#define LCD_END_OF_FRAME_WAIT_COUNT 1
++#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_Bpp(PXAFB_BPP_BITS) | LCCR3_Acb(0xe))
++
++// PCD 21 ist noch ok
++// PIXCLOCK 150000 ergibt LCCR3_PCD von 15
++
+ #endif
+--- linux-2.4.21/include/asm-arm/arch-pxa/hardware.h~ramses
++++ linux-2.4.21/include/asm-arm/arch-pxa/hardware.h
+@@ -127,16 +127,20 @@
+ * Implementation specifics
+ */
+
+-//#ifdef CONFIG_ARCH_LUBBOCK
++#ifdef CONFIG_ARCH_LUBBOCK
+ #include "lubbock.h"
+-//#endif
++#endif
+
+-//#ifdef CONFIG_ARCH_PXA_IDP
++#ifdef CONFIG_ARCH_PXA_IDP
+ #include "idp.h"
+-//#endif
++#endif
+
+-//#ifdef CONFIG_ARCH_PXA_CERF
++#ifdef CONFIG_ARCH_PXA_CERF
+ #include "cerf.h"
+-//#endif
++#endif
++
++#ifdef CONFIG_ARCH_RAMSES
++#include "ramses.h"
++#endif
+
+ #endif /* _ASM_ARCH_HARDWARE_H */
+--- linux-2.4.21/include/asm-arm/arch-pxa/irqs.h~ramses
++++ linux-2.4.21/include/asm-arm/arch-pxa/irqs.h
+@@ -105,14 +105,13 @@
+ #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 defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_PXA_IDP)
+ #if CONFIG_SA1111
+ #define LUBBOCK_IRQ(x) (SA1111_IRQ_MAX + 1 + (x))
+ #else
+@@ -132,6 +131,3 @@
+ #define NR_IRQS (LUBBOCK_LAST_IRQ + 1)
+
+ #endif // CONFIG_ARCH_LUBBOCK
+-
+-
+-
+--- linux-2.4.21/include/asm-arm/arch-pxa/pxa-regs.h~ramses
++++ linux-2.4.21/include/asm-arm/arch-pxa/pxa-regs.h
+@@ -1051,6 +1051,7 @@
+ #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 PMFW __REG(0x40F00034) /* Power Manager Fast-Sleep Wakeup Configuration Register */
+
+ #define PSSR_RDH (1 << 5) /* Read Disable Hold */
+ #define PSSR_PH (1 << 4) /* Peripheral Control Hold */
+--- /dev/null
++++ linux-2.4.21/include/asm-arm/arch-pxa/ramses.h
+@@ -0,0 +1,364 @@
++/*
++ * linux/include/asm-arm/arch-pxa/ramses.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,2003 M&N Logistik-Lösungen Online GmbH
++ *
++ * 2001-09-13: Cliff Brake <cbrake@accelent.com>
++ * Initial code
++ *
++ * 2002-10-08: adaption from PXA IDP to Ramses
++ *
++ */
++
++
++/*
++ * Note: this file must be safe to include in assembly files
++ */
++
++#define RAMSES_FLASH_PHYS (PXA_CS0_PHYS)
++#define RAMSES_ALT_FLASH_PHYS (PXA_CS1_PHYS)
++#define RAMSES_MEDIAQ_PHYS (PXA_CS3_PHYS)
++#define RAMSES_CONTROL_PHYS (PXA_CS4_PHYS)
++#define RAMSES_IDE_PHYS (PXA_CS5_PHYS + 0x03000000)
++#define RAMSES_ETH_PHYS (PXA_CS5_PHYS + 0x03400000)
++#define RAMSES_COREVOLT_PHYS (PXA_CS5_PHYS + 0x03800000)
++#define RAMSES_CPLD_PHYS (PXA_CS5_PHYS + 0x03C00000)
++
++/*
++ * virtual memory map
++ */
++
++#define RAMSES_IDE_BASE (0xf0000000)
++#define RAMSES_IDE_SIZE (1*1024*1024)
++#define RAMSES_ETH_BASE (RAMSES_IDE_BASE + RAMSES_IDE_SIZE)
++#define RAMSES_ETH_SIZE (1*1024*1024)
++#define RAMSES_COREVOLT_BASE (RAMSES_ETH_BASE + RAMSES_ETH_SIZE)
++#define RAMSES_COREVOLT_SIZE (1*1024*1024)
++#define RAMSES_CPLD_BASE (RAMSES_COREVOLT_BASE + RAMSES_COREVOLT_SIZE)
++#define RAMSES_CPLD_SIZE (1*1024*1024)
++#define RAMSES_CONTROL_BASE (RAMSES_CPLD_BASE + RAMSES_CPLD_SIZE)
++#define RAMSES_CONTROL_SIZE (1*1024*1024)
++
++#if (RAMSES_CONTROL_BASE + RAMSES_CONTROL_SIZE) > 0xfc000000
++#error Your custom IO space is getting a bit large !!
++#endif
++
++#define CPLD_P2V(x) ((x) - RAMSES_CPLD_PHYS + RAMSES_CPLD_BASE)
++#define CPLD_V2P(x) ((x) - RAMSES_CPLD_BASE + RAMSES_CPLD_PHYS)
++#define CTRL_P2V(x) ((x) - RAMSES_CONTROL_PHYS + RAMSES_CONTROL_BASE)
++#define CTRL_V2P(x) ((x) - RAMSES_CONTROL_BASE + RAMSES_CONTROL_PHYS)
++#define CORE_P2V(x) ((x) - RAMSES_COREVOLT_PHYS + RAMSES_COREVOLT_BASE)
++#define CORE_V2P(x) ((x) - RAMSES_COREVOLT_BASE + RAMSES_COREVOLT_PHYS)
++
++//smc91111 driver compatibility issue
++#define ETH_BASE RAMSES_ETH_BASE
++
++#ifndef __ASSEMBLY__
++# define __CPLD_REG(x) (*((volatile unsigned long *)CPLD_P2V(x)))
++# define __CTRL_REG(x) (*((volatile unsigned long *)CTRL_P2V(x)))
++# define __CORE_REG(x) (*((volatile unsigned long *)CORE_P2V(x)))
++#else
++# define __CPLD_REG(x) CPLD_P2V(x)
++# define __CTRL_REG(x) CTRL_P2V(x)
++# define __CORE_REG(x) CORE_P2V(x)
++#endif
++
++/* CPLD addresses */
++
++#define RAMSES_CPLD_PERIPH_PWR_ (RAMSES_CPLD_PHYS + 0x04)
++#define RAMSES_CPLD_PERIPH_PWR __CPLD_REG(RAMSES_CPLD_PERIPH_PWR_)
++#define PER_RESET (1 << 4)
++#define PER_PWR_EN (1 << 3)
++#define USB_HOST_PWR_EN (1 << 2)
++#define CORE_VAR_EN (1 << 0)
++
++#define RAMSES_CPLD_LED_CONTROL_ (RAMSES_CPLD_PHYS + 0x08)
++#define RAMSES_CPLD_LED_CONTROL __CPLD_REG(RAMSES_CPLD_LED_CONTROL_)
++#define CPLD_LED2 (1 << 6)
++#define CPLD_LED1 (1 << 5)
++#define GSM_ACTIVE (1 << 4)
++
++#define RAMSES_CPLD_KB_COL_HIGH_ (RAMSES_CPLD_PHYS + 0x0C)
++#define RAMSES_CPLD_KB_COL_HIGH __CPLD_REG(RAMSES_CPLD_KB_COL_HIGH_)
++// kbch(7)..kbch(13) on bit 0..6
++
++#define RAMSES_CPLD_KB_COL_LOW_ (RAMSES_CPLD_PHYS + 0x10)
++#define RAMSES_CPLD_KB_COL_LOW __CPLD_REG(RAMSES_CPLD_KB_COL_LOW_)
++// kbcl(0)..kbch(6) on bit 0..6
++
++#define RAMSES_CPLD_PCCARD_EN_ (RAMSES_CPLD_PHYS + 0x14)
++#define RAMSES_CPLD_PCCARD_EN __CPLD_REG(RAMSES_CPLD_PCCARD_EN_)
++#define PCC1_RESET (1 << 7)
++#define PCC0_RESET (1 << 6)
++#define PCC1_ENABLE (1 << 1)
++#define PCC0_ENABLE (1 << 0)
++
++#define RAMSES_CPLD_PCCARD_PWR_ (RAMSES_CPLD_PHYS + 0x28)
++#define RAMSES_CPLD_PCCARD_PWR __CPLD_REG(RAMSES_CPLD_PCCARD_PWR_)
++#define PCC1_PWR3 (1 << 7)
++#define PCC1_PWR2 (1 << 6)
++#define PCC1_PWR1 (1 << 5)
++#define PCC1_PWR0 (1 << 4)
++#define PCC0_PWR3 (1 << 3)
++#define PCC0_PWR2 (1 << 2)
++#define PCC0_PWR1 (1 << 1)
++#define PCC0_PWR0 (1 << 0)
++
++#define RAMSES_CPLD_MISC_CTRL_ (RAMSES_CPLD_PHYS + 0x2C)
++#define RAMSES_CPLD_MISC_CTRL __CPLD_REG(RAMSES_CPLD_MISC_CTRL_)
++#define RAMSES_IRDA_MD1 (1 << 5)
++#define RAMSES_IRDA_MD0 (1 << 4)
++#define RAMSES_FIR (1 << 3)
++
++#define RAMSES_CPLD_LCD_ (RAMSES_CPLD_PHYS + 0x30)
++#define RAMSES_CPLD_LCD __CPLD_REG(RAMSES_CPLD_LCD_)
++#define RAMSES_LCD_PINC (1 << 7)
++#define RAMSES_LCD_PUP (1 << 6)
++#define RAMSES_LCD_PCS (1 << 5)
++#define RAMSES_LCD_DISPOFF (1 << 2)
++#define RAMSES_LCD_VCC (1 << 0)
++
++#define RAMSES_CPLD_FLASH_WE_ (RAMSES_CPLD_PHYS + 0x34)
++#define RAMSES_CPLD_FLASH_WE __CPLD_REG(RAMSES_CPLD_FLASH_WE_)
++#define RAMSES_FLASH_WE (1 << 0)
++
++/* Read-Only registers */
++
++#define RAMSES_CPLD_KB_ROW_ (RAMSES_CPLD_PHYS + 0x50)
++#define RAMSES_CPLD_KB_ROW __CPLD_REG(RAMSES_CPLD_KB_ROW_)
++// kbr(0)..kbr(6) on bits 0..6
++
++#define RAMSES_CPLD_PCCARD0_STATUS_ (RAMSES_CPLD_PHYS + 0x54)
++#define RAMSES_CPLD_PCCARD0_STATUS __CPLD_REG(RAMSES_CPLD_PCCARD0_STATUS_)
++#define RAMSES_CPLD_PCCARD1_STATUS_ (RAMSES_CPLD_PHYS + 0x58)
++#define RAMSES_CPLD_PCCARD1_STATUS __CPLD_REG(RAMSES_CPLD_PCCARD1_STATUS_)
++#define _PCC_WRPROT (1 << 7)
++#define _PCC_S16 (1 << 7)
++#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 RAMSES_CPLD_MISC_STATUS_ (RAMSES_CPLD_PHYS + 0x5C)
++#define RAMSES_CPLD_MISC_STATUS __CPLD_REG(RAMSES_CPLD_MISC_STATUS_)
++#define RAMSES_MMC_WRPROT (1 << 7)
++#define RAMSES_USB_OVERCURR (1 << 4)
++#define RAMSES_CHG_STS (1 << 2)
++#define RAMSES_WALL_IN (1 << 1)
++#define RAMSES_USB_D_CON (1 << 0)
++
++#define RAMSES_CPLD_YEAR_ (RAMSES_CPLD_PHYS + 0x60)
++#define RAMSES_CPLD_YEAR __CPLD_REG(RAMSES_CPLD_YEAR_)
++
++#define RAMSES_CPLD_MONTH_ (RAMSES_CPLD_PHYS + 0x64)
++#define RAMSES_CPLD_MONTH __CPLD_REG(RAMSES_CPLD_MONTH_)
++
++#define RAMSES_CPLD_DAY_ (RAMSES_CPLD_PHYS + 0x68)
++#define RAMSES_CPLD_DAY __CPLD_REG(RAMSES_CPLD_DAY_)
++
++#define RAMSES_CPLD_REV_ (RAMSES_CPLD_PHYS + 0x6C)
++#define RAMSES_CPLD_REV __CPLD_REG(RAMSES_CPLD_REV_)
++
++#define RAMSES_CPLD_VSTAT_ (RAMSES_CPLD_PHYS + 0x7C)
++#define RAMSES_CPLD_VSTAT __CPLD_REG(RAMSES_CPLD_VSTAT_)
++#define RAMSES_BWE (1 << 1)
++
++
++/* Flags for ramses_flags */
++
++#define RAMSES_FLAGS_LCD_FBTURN (1<<0)
++/* MUST stay bit 0 */
++#define RAMSES_FLAGS_SCANNER_BEAM (1<<1)
++#define RAMSES_FLAGS_KEY_SCAN (1<<2)
++#define RAMSES_FLAGS_KEY_SUSPEND (1<<3)
++#define RAMSES_FLAGS_KEY_OFF (1<<4)
++
++
++/* Offset in SMC EEPROM for LCD type */
++#define RAMSES_LCD_TYPE_OFFSET 0x23
++
++
++/* The control register on the I/O board */
++
++#define RAMSES_CONTROL_ (RAMSES_CONTROL_PHYS + 0)
++#define RAMSES_CONTROL __CTRL_REG(RAMSES_CONTROL_)
++// 5c00 = 0101 1100 0000 0000
++#define RAMSES_CONTROL_SCANNER_TRIG_ (1 << 15)
++#define RAMSES_CONTROL_SCANNER_WAKE_ (1 << 14)
++#define RAMSES_CONTROL_SCANNER_PWR (1 << 13)
++#define RAMSES_CONTROL_LED_BLUE_ (1 << 12)
++
++#define RAMSES_CONTROL_LED_ORANGE_ (1 << 11)
++#define RAMSES_CONTROL_GSM_RESET (1 << 10)
++#define RAMSES_CONTROL_GSM_BOOT (1 << 9)
++#define RAMSES_CONTROL_GSM_PWR (1 << 8)
++
++#define RAMSES_CONTROL_POWEROFF (1 << 7)
++#define RAMSES_CONTROL_USB_INTERN (1 << 6)
++#define RAMSES_CONTROL_MMC_PWR (1 << 5)
++#define RAMSES_CONTROL_UART_PWR (1 << 4)
++
++#define RAMSES_CONTROL_LCD_BLIGHT (1 << 3)
++#define RAMSES_CONTROL_USB (1 << 2)
++
++#define RAMSES_POWER_OFF() { ramses_control_shadow |= RAMSES_CONTROL_POWEROFF; RAMSES_CONTROL = ramses_control_shadow; }
++
++// Active low
++#define RAMSES_SCANNER_TRIG_ON() { ramses_control_shadow &= ~RAMSES_CONTROL_SCANNER_TRIG_; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_SCANNER_TRIG_OFF() { ramses_control_shadow |= RAMSES_CONTROL_SCANNER_TRIG_; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_SCANNER_WAKE_ON() { ramses_control_shadow &= ~RAMSES_CONTROL_SCANNER_WAKE_; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_SCANNER_WAKE_OFF() { ramses_control_shadow |= RAMSES_CONTROL_SCANNER_WAKE_; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_LED_BLUE_ON() { ramses_control_shadow &= ~RAMSES_CONTROL_LED_BLUE_; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_LED_BLUE_OFF() { ramses_control_shadow |= RAMSES_CONTROL_LED_BLUE_; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_LED_ORANGE_ON() { ramses_control_shadow &= ~RAMSES_CONTROL_LED_ORANGE_; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_LED_ORANGE_OFF() { ramses_control_shadow |= RAMSES_CONTROL_LED_ORANGE_; RAMSES_CONTROL = ramses_control_shadow; }
++
++// Active high
++#define RAMSES_SCANNER_ON() { ramses_control_shadow |= RAMSES_CONTROL_SCANNER_PWR; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_SCANNER_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_SCANNER_PWR; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_GSM_RESET_ON() { ramses_control_shadow |= RAMSES_CONTROL_GSM_RESET; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_GSM_RESET_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_GSM_RESET; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_GSM_BOOT_ON() { ramses_control_shadow |= RAMSES_CONTROL_GSM_BOOT; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_GSM_BOOT_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_GSM_BOOT; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_GSM_ON() { ramses_control_shadow |= RAMSES_CONTROL_GSM_PWR; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_GSM_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_GSM_PWR; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_USB_INTERN() { ramses_control_shadow |= RAMSES_CONTROL_USB_INTERN; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_USB_EXTERN() { ramses_control_shadow &= ~RAMSES_CONTROL_USB_INTERN; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_UART_ON() { ramses_control_shadow |= RAMSES_CONTROL_UART_PWR; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_UART_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_UART_PWR; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_MMC_ON() { ramses_control_shadow |= RAMSES_CONTROL_MMC_PWR; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_MMC_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_MMC_PWR; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_LCD_BLIGHT_ON() { ramses_control_shadow |= RAMSES_CONTROL_LCD_BLIGHT; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_LCD_BLIGHT_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_LCD_BLIGHT; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_USB_BUS_ON() { ramses_control_shadow |= RAMSES_CONTROL_USB; RAMSES_CONTROL = ramses_control_shadow; }
++#define RAMSES_USB_BUS_OFF() { ramses_control_shadow &= ~RAMSES_CONTROL_USB; RAMSES_CONTROL = ramses_control_shadow; }
++
++// Corevolt settings
++#define RAMSES_COREVOLT_ (RAMSES_COREVOLT_PHYS)
++#define RAMSES_COREVOLT __CORE_REG(RAMSES_COREVOLT_)
++
++// Battery protocol
++#define HDQ_TMP 0x02
++#define HDQ_LMD 0x05
++#define HDQ_VSB 0x0b
++#define HDQ_CACT 0x0d
++#define HDQ_SAEH 0x0f
++#define HDQ_SAEL 0x10
++#define HDQ_RCAC 0x11
++#define HDQ_DCR 0x18
++
++
++#ifndef __ASSEMBLY__
++
++/* Ramses specific functions */
++void ramses_lcd_power_on(void);
++void ramses_lcd_power_off(void);
++void ramses_lcd_backlight_on(void);
++void ramses_lcd_backlight_off(void);
++void ramses_lcd_set_intensity(int i);
++#ifdef OLDCODE
++void ramses_lcd_set_pwm1(int p);
++#endif
++void ramses_lcd_set_brightness(int b);
++void ramses_lcd_set_contrast(int c);
++int ramses_lcd_get_intensity(void);
++int ramses_lcd_get_brightness(void);
++int ramses_lcd_get_contrast(void);
++int ramses_hdq_get_reg(unsigned char reg);
++void ramses_shut_off(void);
++void ramses_set_corevolt(int volt);
++
++
++/* shadow registers for write only registers */
++extern u16 ramses_control_shadow;
++extern int ramses_corevolt_shadow;
++extern u16 ramses_lcd_type;
++extern int ramses_lcd_pwm1_shadow;
++
++
++/* flag register for various settings */
++extern unsigned int ramses_flags;
++
++/*
++ * macros to write to write only register
++ *
++ * none of these macros are protected from
++ * multiple drivers using them in interrupt context.
++ */
++
++#define WRITE_RAMSES_CONTROL(value, mask) \
++{\
++ ramses_control_shadow = ((value & mask) | (ramses_control_shadow & ~mask));\
++ RAMSES_CONTROL = ramses_control_shadow;\
++}
++#endif
++
++/*
++ * USB Host
++ *
++ * The SL811HS is selected with nCS3 and some address bits:
++ *
++ * 12 8 4
++ * nA14, nCS[3], address mask 1011 1111 1111 0000 = xBf00
++ */
++#define SL811HS_PHYS (PXA_CS3_PHYS+0xBFF0)
++#define SL811HS_DATA (PXA_CS3_PHYS+0xBFF4)
++
++
++
++
++
++
++
++#define PCC_DETECT(x) (GPLR(7 + (x)) & GPIO_bit(7 + (x)))
++
++
++
++
++
++/* A listing of interrupts used by external hardware devices */
++
++#define TOUCH_PANEL_IRQ IRQ_GPIO(21)
++#define TOUCH_PANEL_IRQ_EDGE GPIO_FALLING_EDGE
++
++#define ETHERNET_IRQ IRQ_GPIO(4)
++#define ETHERNET_IRQ_EDGE GPIO_RISING_EDGE
++
++#define CFCARD_CD_VALID IRQ_GPIO(8)
++#define CFCARD_CD_VALID_EDGE GPIO_BOTH_EDGES
++
++#define CFCARD_RDYINT IRQ_GPIO(22)
++
++#define RAMSES_KEYBOARD_IRQ IRQ_GPIO(3)
++#define RAMSES_KEYBOARD_IRQ_EDGE GPIO_FALLING_EDGE
++
++#define SL811HS_IRQ IRQ_GPIO(32)
++#define SL811HS_IRQ_EDGE GPIO_RISING_EDGE
++
++/*
++ * Macros for LED Driver
++ */
++
++/* leds 0 = ON */
++#define RAMSES_HB_LED (1<<5)
++#define RAMSES_BUSY_LED (1<<6)
++
++#define RAMSES_LEDS_MASK (RAMSES_HB_LED | RAMSES_BUSY_LED)
++
++#define RAMSES_WRITE_LEDS(value) (RAMSES_CPLD_LED_CONTROL = ((RAMSES_CPLD_LED_CONTROL & ~(RAMSES_LEDS_MASK)) | value))
++
++/*
++ * macros for MTD driver
++ */
++
++#define FLASH_WRITE_PROTECT_DISABLE() ((RAMSES_CPLD_FLASH_WE) &= ~(0x1))
++#define FLASH_WRITE_PROTECT_ENABLE() ((RAMSES_CPLD_FLASH_WE) |= (0x1))
++
++
+--- linux-2.4.21/include/asm-arm/arch-pxa/time.h~pxa-timerint
++++ linux-2.4.21/include/asm-arm/arch-pxa/time.h
+@@ -33,7 +33,7 @@
+ /* IRQs are disabled before entering here from do_gettimeofday() */
+ static unsigned long pxa_gettimeoffset (void)
+ {
+- unsigned long ticks_to_match, elapsed, usec;
++ long ticks_to_match, elapsed, usec;
+
+ /* Get ticks before next timer match */
+ ticks_to_match = OSMR0 - OSCR;
+@@ -41,6 +41,10 @@
+ /* We need elapsed ticks since last match */
+ elapsed = LATCH - ticks_to_match;
+
++ /* don't get fooled by the workaround in pxa_timer_interrupt() */
++ if (elapsed <= 0)
++ return 0;
++
+ /* Now convert them to usec */
+ usec = (unsigned long)(elapsed*tick)/LATCH;
+
+@@ -59,6 +63,15 @@
+ * 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.
++ *
++ * HACK ALERT: it seems that the PXA timer regs aren't updated right
++ * away in all cases when a write occurs. We therefore compare with
++ * 8 instead of 0 in the while() condition below to avoid missing a
++ * match if OSCR has already reached the next OSMR value.
++ * Experience has shown that up to 6 ticks are needed to work around
++ * this problem, but let's use 8 to be conservative. Note that this
++ * affect things only when the timer IRQ has been delayed by nearly
++ * exactly one tick period which should be a pretty rare event.
+ */
+ do {
+ do_leds();
+@@ -68,7 +81,7 @@
+ OSSR = OSSR_M0; /* Clear match on timer 0 */
+ next_match = (OSMR0 += LATCH);
+ restore_flags( flags );
+- } while( (signed long)(next_match - OSCR) <= 0 );
++ } while( (signed long)(next_match - OSCR) <= 8 );
+ }
+
+ extern inline void setup_timer (void)
+--- /dev/null
++++ linux-2.4.21/include/asm-arm/sl811-hw.h
+@@ -0,0 +1,202 @@
++/*
++File: include/asm-arm/sl811-hw.h
++
++19.09.2003 hne@ist1.de
++Use Kernel 2.4.20 and this source from 2.4.22
++Splitt hardware depens into file sl811-x86.h and sl811-arm.h.
++Functions as inline.
++
++23.09.2003 hne
++Move Hardware depend header sl811-arm.h into include/asm-arm/sl811-hw.h.
++GPRD as parameter.
++
++24.09.2003 hne
++Use Offset from ADDR to DATA instand of direct io.
++
++03.10.2003 hne
++Low level only for port io into hardware-include.
++*/
++
++#ifndef __LINUX_SL811_HW_H
++#define __LINUX_SL811_HW_H
++
++#ifdef CONFIG_X86
++#define MAX_CONTROLERS 1 /* Max number of sl811 controllers */
++ /* Always 1 for this architecture! */
++
++#define SIZEOF_IO_REGION 1 /* Size for request/release region */
++
++#define OFFSET_DATA_REG data_off /* Offset from ADDR_IO to DATA_IO (future) */
++ /* Can change by arg */
++
++static int io = 0xf100000e; /* Base addr_io */
++static int data_off = 1; /* Offset from addr_io to addr_io */
++static int irq = 44; /* also change gprd !!! */
++static int gprd = 23; /* also change irq !!! */
++
++MODULE_PARM(io,"i");
++MODULE_PARM_DESC(io,"sl811 address io port 0xf100000e");
++MODULE_PARM(data_off,"i");
++MODULE_PARM_DESC(data_off,"sl811 data io port offset from address port (default 1)");
++MODULE_PARM(irq,"i");
++MODULE_PARM_DESC(irq,"sl811 irq 44(default)");
++MODULE_PARM(gprd,"i");
++MODULE_PARM_DESC(gprd,"sl811 GPRD port 23(default)");
++#endif
++
++#ifdef CONFIG_ARCH_RAMSES
++#define SIZEOF_IO_REGION 8 /* Size for request/release region */
++static void *ramses_sl811hs; /* dynamically assign virtual address */
++#endif
++
++
++/*
++ * Low level: Read from Data port [arm]
++ */
++static __u8 inline sl811_read_data (struct sl811_hc *hc)
++{
++ __u8 data;
++ data = readb(hc->data_io);
++ rmb();
++//printk("%s: in %08p %02x\n", __FUNCTION__, hc->data_io, data);
++ return data;
++}
++
++/*
++ * Low level: Write to index register [arm]
++ */
++static void inline sl811_write_index (struct sl811_hc *hc, __u8 index)
++{
++//printk("%s: out %08p %02x\n", __FUNCTION__, hc->addr_io, index);
++ writeb(index, hc->addr_io);
++ wmb();
++}
++
++/*
++ * Low level: Write to Data port [arm]
++ */
++static void inline sl811_write_data (struct sl811_hc *hc, __u8 data)
++{
++//printk("%s: out %08p %02x\n", __FUNCTION__, hc->data_io, data);
++ writeb(data, hc->data_io);
++ wmb();
++}
++
++/*
++ * Low level: Write to index register and data port [arm]
++ */
++static void inline sl811_write_index_data (struct sl811_hc *hc, __u8 index, __u8 data)
++{
++ writeb(index, hc->addr_io);
++//printk("%s: out %08p %02x\n", __FUNCTION__, hc->addr_io, index);
++ writeb(data, hc->data_io);
++//printk("%s: out %08p %02x\n", __FUNCTION__, hc->data_io, data);
++ wmb();
++}
++
++
++/*
++ * This function is board specific. It sets up the interrupt to
++ * be an edge trigger and trigger on the rising edge
++ */
++static void inline sl811_init_irq(void)
++{
++#ifdef CONFIG_X86
++ GPDR &= ~(1<<gprd);
++ set_GPIO_IRQ_edge(1<<gprd, GPIO_RISING_EDGE);
++#endif
++#ifdef CONFIG_ARCH_PXA
++ int irq_gpio_pin = IRQ_TO_GPIO_2_80(SL811HS_IRQ);
++ GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin);
++ set_GPIO_IRQ_edge(irq_gpio_pin, SL811HS_IRQ_EDGE);
++#endif
++}
++
++/*****************************************************************
++ *
++ * Function Name: release_regions [arm]
++ *
++ * This function is board specific. It release all io address
++ * from memory (if can).
++ *
++ * Input: struct sl811_hc * *
++ *
++ * Return value : 0 = OK
++ *
++ *****************************************************************/
++static void inline sl811_release_regions(struct sl811_hc *hc)
++{
++#ifdef CONFIG_X86
++ if (hc->addr_io)
++ release_region(hc->addr_io, SIZEOF_IO_REGION);
++ hc->addr_io = 0;
++
++ if (hc->data_io)
++ release_region(hc->data_io, SIZEOF_IO_REGION);
++ hc->data_io = 0;
++#endif
++#ifdef CONFIG_ARCH_RAMSES
++ if (ramses_sl811hs) {
++ iounmap(ramses_sl811hs);
++ release_mem_region(SL811HS_PHYS, SIZEOF_IO_REGION);
++ }
++ hc->addr_io = 0;
++ hc->data_io = 0;
++ RAMSES_CPLD_PERIPH_PWR &= ~USB_HOST_PWR_EN;
++ RAMSES_USB_BUS_OFF();
++#endif
++}
++
++/*****************************************************************
++ *
++ * Function Name: request_regions [arm]
++ *
++ * This function is board specific. It request all io address and
++ * maps into memory (if can).
++ *
++ * Input: struct sl811_hc *
++ *
++ * Return value : 0 = OK
++ *
++ *****************************************************************/
++static int inline sl811_request_regions (struct sl811_hc *hc, int addr_io, int data_io, const char *name)
++{
++#ifdef CONFIG_X86
++ if (!request_region(addr_io, SIZEOF_IO_REGION, name)) {
++ PDEBUG(3, "request address %d failed", addr_io);
++ return -EBUSY;
++ }
++ hc->addr_io = addr_io;
++
++ if (!request_region(data_io, SIZEOF_IO_REGION, MODNAME)) {
++ PDEBUG(3, "request address %d failed", data_io);
++ /* release_region(hc->addr_io, SIZEOF_IO_REGION); */
++ return -EBUSY;
++ }
++ hc->data_io = data_io;
++#endif
++#ifdef CONFIG_ARCH_RAMSES
++ RAMSES_USB_BUS_ON();
++ RAMSES_CPLD_PERIPH_PWR |= USB_HOST_PWR_EN;
++ mdelay(300);
++
++ if (!request_mem_region(SL811HS_PHYS, SIZEOF_IO_REGION, name)) {
++ printk(KERN_ERR "unable to reserve region\n");
++ return -EBUSY;
++ } else {
++ ramses_sl811hs = ioremap_nocache(SL811HS_PHYS, SIZEOF_IO_REGION);
++ dbg("phys %p -> virt %p\n", SL811HS_PHYS, ramses_sl811hs);
++ if (!ramses_sl811hs) {
++ printk(KERN_ERR "unable to map region\n");
++ release_mem_region(SL811HS_PHYS, SIZEOF_IO_REGION);
++ return -EBUSY;
++ }
++ }
++ hc->addr_io = (unsigned long) ramses_sl811hs;
++ hc->data_io = (unsigned long) ramses_sl811hs+4;
++#endif
++
++ return 0;
++}
++
++#endif // __LINUX_SL811_HW_H
+--- linux-2.4.21/include/linux/apm_bios.h~pm
++++ linux-2.4.21/include/linux/apm_bios.h
+@@ -16,6 +16,8 @@
+ * General Public License for more details.
+ */
+
++#include <linux/pm-devices.h>
++
+ typedef unsigned short apm_event_t;
+ typedef unsigned short apm_eventinfo_t;
+
+@@ -59,6 +61,16 @@
+ };
+
+ /*
++ * Allow device specific code to register function which
++ * gets the battery power status (see arch/arm/mach-pxa/apm.c).
++ */
++extern void apm_register_get_power_status( int (*fn)(u_char *ac_line_status,
++ u_char *battery_status,
++ u_char *battery_flag,
++ u_char *battery_percentage,
++ u_short *battery_life));
++
++/*
+ * The APM function codes
+ */
+ #define APM_FUNC_INST_CHECK 0x5300
+@@ -168,6 +180,7 @@
+ /*
+ * APM Device IDs
+ */
++#ifdef _i386_
+ #define APM_DEVICE_BIOS 0x0000
+ #define APM_DEVICE_ALL 0x0001
+ #define APM_DEVICE_DISPLAY 0x0100
+@@ -181,6 +194,21 @@
+ #define APM_DEVICE_OLD_ALL 0xffff
+ #define APM_DEVICE_CLASS 0x00ff
+ #define APM_DEVICE_MASK 0xff00
++#endif
++
++/*
++ * APM devices IDs for non-x86
++ */
++#define APM_DEVICE_ALL PM_SYS_DEV
++#define APM_DEVICE_DISPLAY PM_DISPLAY_DEV
++#define APM_DEVICE_STORAGE PM_STORAGE_DEV
++#define APM_DEVICE_PARALLEL PM_PARALLEL_DEV
++#define APM_DEVICE_SERIAL PM_SERIAL_DEV
++#define APM_DEVICE_NETWORK PM_NETWORK_DEV
++#define APM_DEVICE_PCMCIA PM_PCMCIA_DEV
++#define APM_DEVICE_BATTERY PM_BATTERY_DEV
++#define APM_DEVICE_TPANEL PM_TPANEL_DEV
++
+
+ #ifdef __KERNEL__
+ /*
+@@ -214,5 +242,6 @@
+
+ #define APM_IOC_STANDBY _IO('A', 1)
+ #define APM_IOC_SUSPEND _IO('A', 2)
++#define APM_IOC_SET_WAKEUP _IO('A', 3)
+
+ #endif /* LINUX_APM_H */
+--- linux-2.4.21/include/linux/i2c-id.h~i2c-ds1337
++++ linux-2.4.21/include/linux/i2c-id.h
+@@ -95,13 +95,14 @@
+ #define I2C_DRIVERID_ADV717x 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_24LC32A 51 /* Microchip 24LC32A 32k EEPROM */
++#define I2C_DRIVERID_DS1337 52 /* DS1337 real time clock */
+
+
+
+-#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_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
+--- /dev/null
++++ linux-2.4.21/include/linux/pm-devices.h
+@@ -0,0 +1,41 @@
++#ifndef _LINUX_PM_DEV_H
++#define _LINUX_PM_DEV_H
++
++/*
++ * Copyright 2002 Montavista Software (mlocke@mvista.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2, 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.
++ */
++
++
++
++/*
++ * Device types
++ */
++enum
++{
++ PM_UNKNOWN_DEV = 0, /* generic */
++ PM_SYS_DEV, /* system device (fan, KB controller, ...) */
++ PM_PCI_DEV, /* PCI device */
++ PM_USB_DEV, /* USB device */
++ PM_SCSI_DEV, /* SCSI device */
++ PM_ISA_DEV, /* ISA device */
++ PM_MTD_DEV, /* Memory Technology Device */
++ PM_TPANEL_DEV, /* Memory Technology Device */
++ PM_STORAGE_DEV, /* Memory Technology Device */
++ PM_NETWORK_DEV, /* Memory Technology Device */
++ PM_PCMCIA_DEV, /* Memory Technology Device */
++ PM_DISPLAY_DEV, /* Memory Technology Device */
++ PM_SERIAL_DEV, /* Memory Technology Device */
++ PM_BATTERY_DEV, /* Memory Technology Device */
++};
++
++#endif
+--- linux-2.4.21/include/linux/pm.h~pm
++++ linux-2.4.21/include/linux/pm.h
+@@ -24,6 +24,7 @@
+ #ifdef __KERNEL__
+
+ #include <linux/config.h>
++#include <linux/pm-devices.h>
+ #include <linux/list.h>
+
+ /*
+@@ -49,20 +50,6 @@
+ };
+
+ typedef int pm_request_t;
+-
+-/*
+- * Device types
+- */
+-enum
+-{
+- PM_UNKNOWN_DEV = 0, /* generic */
+- PM_SYS_DEV, /* system device (fan, KB controller, ...) */
+- PM_PCI_DEV, /* PCI device */
+- PM_USB_DEV, /* USB device */
+- PM_SCSI_DEV, /* SCSI device */
+- PM_ISA_DEV, /* ISA device */
+- PM_MTD_DEV, /* Memory Technology Device */
+-};
+
+ typedef int pm_dev_t;
+
+--- linux-2.4.21/include/linux/soundcard.h~ucb1x00
++++ linux-2.4.21/include/linux/soundcard.h
+@@ -811,6 +811,7 @@
+ #define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */
+ #define SOUND_MIXER_OUTSRC 0xfa /* Arg contains a bit for each input source to output */
+ #define SOUND_MIXER_OUTMASK 0xf9 /* Arg contains a bit for each supported input source to output */
++#define SOUND_MIXER_AC97 0xf8 /* directly access ac97 registers */
+
+ /* Device mask bits */
+
+@@ -874,6 +875,7 @@
+ #define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK)
+ #define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS)
+ #define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS)
++#define SOUND_MIXER_READ_AC97 MIXER_READ(SOUND_MIXER_AC97)
+
+ #define MIXER_WRITE(dev) _SIOWR('M', dev, int)
+ #define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME)
+@@ -900,6 +902,7 @@
+ #define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD)
+
+ #define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC)
++#define SOUND_MIXER_WRITE_AC97 MIXER_WRITE(SOUND_MIXER_AC97)
+
+ typedef struct mixer_info
+ {
+--- linux-2.4.21/include/linux/tty.h~ramses-lcd
++++ linux-2.4.21/include/linux/tty.h
+@@ -10,8 +10,8 @@
+ * resizing).
+ */
+ #define MIN_NR_CONSOLES 1 /* must be at least 1 */
+-#define MAX_NR_CONSOLES 63 /* serial lines start at 64 */
+-#define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */
++#define MAX_NR_CONSOLES 3 /* serial lines start at 64 */
++#define MAX_NR_USER_CONSOLES 3 /* must be root to allocate above this */
+ /* Note: the ioctl VT_GETSTATE does not work for
+ consoles 16 and higher (since it returns a short) */
+
+--- linux-2.4.21/include/linux/usb.h~ramses-usb
++++ linux-2.4.21/include/linux/usb.h
+@@ -1079,7 +1079,7 @@
+ void usb_show_string(struct usb_device *dev, char *id, int index);
+
+ #ifdef DEBUG
+-#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
++#define dbg(format, arg...) printk(__FILE__ ": " format "\n" , ## arg)
+ #else
+ #define dbg(format, arg...) do {} while (0)
+ #endif
+--- linux-2.4.21/include/linux/wireless.h~linux-iw241_we16-6
++++ linux-2.4.21/include/linux/wireless.h
+@@ -1,7 +1,7 @@
+ /*
+ * This file define a set of standard wireless extensions
+ *
+- * Version : 15 12.7.02
++ * Version : 16 2.4.03
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+@@ -69,6 +69,8 @@
+
+ /***************************** INCLUDES *****************************/
+
++/* To minimise problems in user space, I might remove those headers
++ * at some point. Jean II */
+ #include <linux/types.h> /* for "caddr_t" et al */
+ #include <linux/socket.h> /* for "struct sockaddr" et al */
+ #include <linux/if.h> /* for IFNAMSIZ and co... */
+@@ -80,7 +82,7 @@
+ * (there is some stuff that will be added in the future...)
+ * I just plan to increment with each new version.
+ */
+-#define WIRELESS_EXT 15
++#define WIRELESS_EXT 16
+
+ /*
+ * Changes :
+@@ -163,6 +165,16 @@
+ * - Add IW_TXPOW_RANGE for range of Tx Powers
+ * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
+ * - Add IW_MODE_MONITOR for passive monitor
++ *
++ * V15 to V16
++ * ----------
++ * - Increase the number of bitrates in iw_range to 32 (for 802.11g)
++ * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a)
++ * - Reshuffle struct iw_range for increases, add filler
++ * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses
++ * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support
++ * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
++ * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index
+ */
+
+ /**************************** CONSTANTS ****************************/
+@@ -196,9 +208,11 @@
+ /* 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 (statistics per MAC address) */
++/* Spy support (statistics per MAC address - used for Mobile IP support) */
+ #define SIOCSIWSPY 0x8B10 /* set spy addresses */
+ #define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */
++#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */
++#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */
+
+ /* Access Point manipulation */
+ #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */
+@@ -294,7 +308,7 @@
+ #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 */
++#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */
+
+ #define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */
+
+@@ -306,13 +320,13 @@
+ /* ----------------------- OTHER CONSTANTS ----------------------- */
+
+ /* Maximum frequencies in the range struct */
+-#define IW_MAX_FREQUENCIES 16
++#define IW_MAX_FREQUENCIES 32
+ /* Note : if you have something like 80 frequencies,
+ * don't increase this constant and don't fill the frequency list.
+ * The user will be able to set by channel anyway... */
+
+ /* Maximum bit rates in the range struct */
+-#define IW_MAX_BITRATES 8
++#define IW_MAX_BITRATES 32
+
+ /* Maximum tx powers in the range struct */
+ #define IW_MAX_TXPOWER 8
+@@ -320,8 +334,7 @@
+ * a few of them in the struct iw_range. */
+
+ /* Maximum of address that you may set with SPY */
+-#define IW_MAX_SPY 8 /* set */
+-#define IW_MAX_GET_SPY 64 /* get */
++#define IW_MAX_SPY 8
+
+ /* Maximum of address that you may get in the
+ list of access points in range */
+@@ -354,7 +367,8 @@
+ #define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */
+ #define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */
+ #define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */
+-#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */
++#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */
++#define IW_ENCODE_TEMP 0x0400 /* Temporary key */
+
+ /* Power management flags available (along with the value, if any) */
+ #define IW_POWER_ON 0x0000 /* No details... */
+@@ -482,6 +496,17 @@
+ __u32 beacon; /* Missed beacons/superframe */
+ };
+
++/*
++ * Quality range (for spy threshold)
++ */
++struct iw_thrspy
++{
++ struct sockaddr addr; /* Source address (hw/mac) */
++ struct iw_quality qual; /* Quality of the link */
++ struct iw_quality low; /* Low threshold */
++ struct iw_quality high; /* High threshold */
++};
++
+ /* ------------------------ WIRELESS STATS ------------------------ */
+ /*
+ * Wireless statistics (used for /proc/net/wireless)
+@@ -534,7 +559,7 @@
+ struct iw_quality qual; /* Quality part of statistics */
+
+ struct sockaddr ap_addr; /* Access point address */
+- struct sockaddr addr; /* Destination address (hw) */
++ struct sockaddr addr; /* Destination address (hw/mac) */
+
+ struct iw_param param; /* Other small parameters */
+ struct iw_point data; /* Other large parameters */
+@@ -582,17 +607,31 @@
+ __u32 min_nwid; /* Minimal NWID we are able to set */
+ __u32 max_nwid; /* Maximal NWID we are able to set */
+
+- /* Frequency */
+- __u16 num_channels; /* Number of channels [0; num - 1] */
+- __u8 num_frequency; /* Number of entry in the list */
+- struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */
+- /* Note : this frequency list doesn't need to fit channel numbers */
++ /* Old Frequency (backward compat - moved lower ) */
++ __u16 old_num_channels;
++ __u8 old_num_frequency;
++ /* Filler to keep "version" at the same offset */
++ __s32 old_freq[6];
+
+ /* signal level threshold range */
+ __s32 sensitivity;
+
+ /* Quality of link & SNR stuff */
++ /* Quality range (link, level, noise)
++ * If the quality is absolute, it will be in the range [0 ; max_qual],
++ * if the quality is dBm, it will be in the range [max_qual ; 0].
++ * Don't forget that we use 8 bit arithmetics... */
+ struct iw_quality max_qual; /* Quality of the link */
++ /* This should contain the average/typical values of the quality
++ * indicator. This should be the threshold between a "good" and
++ * a "bad" link (example : monitor going from green to orange).
++ * Currently, user space apps like quality monitors don't have any
++ * way to calibrate the measurement. With this, they can split
++ * the range between 0 and max_qual in different quality level
++ * (using a geometric subdivision centered on the average).
++ * I expect that people doing the user space apps will feedback
++ * us on which value we need to put in each driver... */
++ struct iw_quality avg_qual; /* Quality of the link */
+
+ /* Rates */
+ __u8 num_bitrates; /* Number of entries in the list */
+@@ -619,6 +658,8 @@
+ __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */
+ __u8 num_encoding_sizes; /* Number of entry in the list */
+ __u8 max_encoding_tokens; /* Max number of tokens */
++ /* For drivers that need a "login/passwd" form */
++ __u8 encoding_login_index; /* token index for login token */
+
+ /* Transmit power */
+ __u16 txpower_capa; /* What options are supported */
+@@ -638,18 +679,12 @@
+ __s32 min_r_time; /* Minimal retry lifetime */
+ __s32 max_r_time; /* Maximal retry lifetime */
+
+- /* Average quality of link & SNR */
+- struct iw_quality avg_qual; /* Quality of the link */
+- /* This should contain the average/typical values of the quality
+- * indicator. This should be the threshold between a "good" and
+- * a "bad" link (example : monitor going from green to orange).
+- * Currently, user space apps like quality monitors don't have any
+- * way to calibrate the measurement. With this, they can split
+- * the range between 0 and max_qual in different quality level
+- * (using a geometric subdivision centered on the average).
+- * I expect that people doing the user space apps will feedback
+- * us on which value we need to put in each driver...
+- */
++ /* Frequency */
++ __u16 num_channels; /* Number of channels [0; num - 1] */
++ __u8 num_frequency; /* Number of entry in the list */
++ struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */
++ /* Note : this frequency list doesn't need to fit channel numbers,
++ * because each entry contain its channel index */
+ };
+
+ /*
+--- linux-2.4.21/include/net/iw_handler.h~linux-iw241_we16-6
++++ linux-2.4.21/include/net/iw_handler.h
+@@ -1,7 +1,7 @@
+ /*
+ * This file define the new driver API for Wireless Extensions
+ *
+- * Version : 4 21.6.02
++ * Version : 5 4.12.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 4
++#define IW_HANDLER_VERSION 5
+
+ /*
+ * Changes :
+@@ -220,10 +220,18 @@
+ * V3 to V4
+ * --------
+ * - Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
++ *
++ * V4 to V5
++ * --------
++ * - Add new spy support : struct iw_spy_data & prototypes
+ */
+
+ /**************************** CONSTANTS ****************************/
+
++/* Enable enhanced spy support. Disable to reduce footprint */
++#define IW_WIRELESS_SPY
++#define IW_WIRELESS_THRSPY
++
+ /* Special error message for the driver to indicate that we
+ * should do a commit after return from the iw_handler */
+ #define EIWCOMMIT EINPROGRESS
+@@ -315,6 +323,9 @@
+ * We will automatically export that to user space... */
+ struct iw_priv_args * private_args;
+
++ /* Driver enhanced spy support */
++ long spy_offset; /* Spy data offset */
++
+ /* In the long term, get_wireless_stats will move from
+ * 'struct net_device' to here, to minimise bloat. */
+ };
+@@ -350,6 +361,33 @@
+
+ /* Need to think of short header translation table. Later. */
+
++/* --------------------- ENHANCED SPY SUPPORT --------------------- */
++/*
++ * In the old days, the driver was handling spy support all by itself.
++ * Now, the driver can delegate this task to Wireless Extensions.
++ * It needs to include this struct in its private part and use the
++ * standard spy iw_handler.
++ */
++
++/*
++ * Instance specific spy data, i.e. addresses spied and quality for them.
++ */
++struct iw_spy_data
++{
++#ifdef IW_WIRELESS_SPY
++ /* --- Standard spy support --- */
++ int spy_number;
++ u_char spy_address[IW_MAX_SPY][ETH_ALEN];
++ struct iw_quality spy_stat[IW_MAX_SPY];
++#ifdef IW_WIRELESS_THRSPY
++ /* --- Enhanced spy support (event) */
++ struct iw_quality spy_thr_low; /* Low threshold */
++ struct iw_quality spy_thr_high; /* High threshold */
++ u_char spy_thr_under[IW_MAX_SPY];
++#endif /* IW_WIRELESS_THRSPY */
++#endif /* IW_WIRELESS_SPY */
++};
++
+ /**************************** PROTOTYPES ****************************/
+ /*
+ * Functions part of the Wireless Extensions (defined in net/core/wireless.c).
+@@ -375,6 +413,31 @@
+
+ /* We may need a function to send a stream of events to user space.
+ * More on that later... */
++
++/* Standard handler for SIOCSIWSPY */
++extern int iw_handler_set_spy(struct net_device * dev,
++ struct iw_request_info * info,
++ union iwreq_data * wrqu,
++ char * extra);
++/* Standard handler for SIOCGIWSPY */
++extern int iw_handler_get_spy(struct net_device * dev,
++ struct iw_request_info * info,
++ union iwreq_data * wrqu,
++ char * extra);
++/* Standard handler for SIOCSIWTHRSPY */
++extern int iw_handler_set_thrspy(struct net_device * dev,
++ struct iw_request_info *info,
++ union iwreq_data * wrqu,
++ char * extra);
++/* Standard handler for SIOCGIWTHRSPY */
++extern int iw_handler_get_thrspy(struct net_device * dev,
++ struct iw_request_info *info,
++ union iwreq_data * wrqu,
++ char * extra);
++/* Driver call to update spy records */
++extern void wireless_spy_update(struct net_device * dev,
++ unsigned char * address,
++ struct iw_quality * wstats);
+
+ /************************* INLINE FUNTIONS *************************/
+ /*
+--- linux-2.4.21/init/do_mounts.c~small-nocramdisk
++++ linux-2.4.21/init/do_mounts.c
+@@ -16,8 +16,6 @@
+ #include <linux/ext2_fs.h>
+ #include <linux/romfs_fs.h>
+
+-#define BUILD_CRAMDISK
+-
+ extern int get_filesystem_list(char * buf);
+
+ extern asmlinkage long sys_mount(char *dev_name, char *dir_name, char *type,
+--- linux-2.4.21/kernel/ksyms.c~ramses
++++ linux-2.4.21/kernel/ksyms.c
+@@ -585,6 +585,11 @@
+
+ EXPORT_SYMBOL(tasklist_lock);
+ EXPORT_SYMBOL(pidhash);
++#ifdef CONFIG_ARCH_RAMSES
++#include <asm/arch/ramses.h>
++EXPORT_SYMBOL(ramses_control_shadow);
++EXPORT_SYMBOL(ramses_flags);
++#endif
+
+ /* debug */
+ EXPORT_SYMBOL(dump_stack);
+--- linux-2.4.21/kernel/pm.c~pm
++++ linux-2.4.21/kernel/pm.c
+@@ -234,7 +234,7 @@
+ struct list_head *entry;
+
+ down(&pm_devs_lock);
+- entry = pm_devs.next;
++ entry = (rqst==PM_RESUME) ? pm_devs.prev : pm_devs.next;
+ while (entry != &pm_devs) {
+ struct pm_dev *dev = list_entry(entry, struct pm_dev, entry);
+ if (dev->callback) {
+@@ -249,7 +249,7 @@
+ return status;
+ }
+ }
+- entry = entry->next;
++ entry = (rqst==PM_RESUME) ? entry->prev : entry->next;
+ }
+ up(&pm_devs_lock);
+ return 0;
+--- linux-2.4.21/mm/swap.c~swap-performance
++++ linux-2.4.21/mm/swap.c
+@@ -28,7 +28,7 @@
+ int page_cluster;
+
+ pager_daemon_t pager_daemon = {
+- 512, /* base number for calculating the number of tries */
++ 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 */
+ };
+--- linux-2.4.21/mm/vmalloc.c~vmalloc
++++ linux-2.4.21/mm/vmalloc.c
+@@ -183,6 +183,9 @@
+ return NULL;
+
+ size += PAGE_SIZE;
++#ifdef VMALLOC_ALIGN
++ size = (size + VMALLOC_ALIGN - 1) & ~(VMALLOC_ALIGN - 1);
++#endif
+ if (!size) {
+ kfree (area);
+ return NULL;
+--- linux-2.4.21/net/core/wireless.c~linux-iw241_we16-6
++++ linux-2.4.21/net/core/wireless.c
+@@ -2,7 +2,7 @@
+ * This file implement the Wireless Extensions APIs.
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+@@ -43,6 +43,11 @@
+ * 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)
++ *
++ * v6 - 9.01.03 - Jean II
++ * o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
++ * o Add enhanced spy support : iw_handler_set_thrspy() and event.
++ * o Add WIRELESS_EXT version display in /proc/net/wireless
+ */
+
+ /***************************** INCLUDES *****************************/
+@@ -52,6 +57,7 @@
+ #include <linux/types.h> /* off_t */
+ #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */
+ #include <linux/rtnetlink.h> /* rtnetlink stuff */
++#include <linux/if_arp.h> /* ARPHRD_ETHER */
+
+ #include <linux/wireless.h> /* Pretty obvious */
+ #include <net/iw_handler.h> /* New driver API */
+@@ -65,6 +71,7 @@
+ /* Debuging stuff */
+ #undef WE_IOCTL_DEBUG /* Debug IOCTL API */
+ #undef WE_EVENT_DEBUG /* Debug Event dispatcher */
++#undef WE_SPY_DEBUG /* Debug enhanced spy support */
+
+ /* Options */
+ #define WE_EVENT_NETLINK /* Propagate events using rtnetlink */
+@@ -72,7 +79,7 @@
+
+ /************************* GLOBAL VARIABLES *************************/
+ /*
+- * You should not use global variables, because or re-entrancy.
++ * You should not use global variables, because of re-entrancy.
+ * On our case, it's only const, so it's OK...
+ */
+ /*
+@@ -115,11 +122,11 @@
+ /* 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_GET_SPY, 0},
+- /* -- hole -- */
+- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+- /* -- hole -- */
+- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
++ /* SIOCSIWTHRSPY */
++ { IW_HEADER_TYPE_POINT, 0, sizeof(struct iw_thrspy), 1, 1, 0},
++ /* SIOCGIWTHRSPY */
++ { IW_HEADER_TYPE_POINT, 0, sizeof(struct iw_thrspy), 1, 1, 0},
+ /* SIOCSIWAP */
+ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+ /* SIOCGIWAP */
+@@ -377,9 +384,9 @@
+ 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"
+- );
++ "Inter-| sta-| Quality | Discarded packets | Missed | WE\n"
++ " face | tus | link level noise | nwid crypt frag retry misc | beacon | %d\n",
++ WIRELESS_EXT);
+
+ pos += size;
+ len += size;
+@@ -1023,4 +1030,253 @@
+ kfree(event);
+
+ return; /* Always success, I guess ;-) */
++}
++
++/********************** ENHANCED IWSPY SUPPORT **********************/
++/*
++ * In the old days, the driver was handling spy support all by itself.
++ * Now, the driver can delegate this task to Wireless Extensions.
++ * It needs to use those standard spy iw_handler in struct iw_handler_def,
++ * push data to us via XXX and include struct iw_spy_data in its
++ * private part.
++ * One of the main advantage of centralising spy support here is that
++ * it becomes much easier to improve and extend it without having to touch
++ * the drivers. One example is the addition of the Spy-Threshold events.
++ * Note : IW_WIRELESS_SPY is defined in iw_handler.h
++ */
++
++/*------------------------------------------------------------------*/
++/*
++ * Standard Wireless Handler : set Spy List
++ */
++int iw_handler_set_spy(struct net_device * dev,
++ struct iw_request_info * info,
++ union iwreq_data * wrqu,
++ char * extra)
++{
++#ifdef IW_WIRELESS_SPY
++ struct iw_spy_data * spydata = (dev->priv +
++ dev->wireless_handlers->spy_offset);
++ struct sockaddr * address = (struct sockaddr *) extra;
++
++ /* Disable spy collection while we copy the addresses.
++ * As we don't disable interrupts, we need to do this to avoid races.
++ * As we are the only writer, this is good enough. */
++ spydata->spy_number = 0;
++
++ /* Are there are addresses to copy? */
++ if(wrqu->data.length > 0) {
++ int i;
++
++ /* Copy addresses */
++ for(i = 0; i < wrqu->data.length; i++)
++ memcpy(spydata->spy_address[i], address[i].sa_data,
++ ETH_ALEN);
++ /* Reset stats */
++ memset(spydata->spy_stat, 0,
++ sizeof(struct iw_quality) * IW_MAX_SPY);
++
++#ifdef WE_SPY_DEBUG
++ printk(KERN_DEBUG "iw_handler_set_spy() : offset %ld, spydata %p, num %d\n", dev->wireless_handlers->spy_offset, spydata, wrqu->data.length);
++ for (i = 0; i < wrqu->data.length; i++)
++ printk(KERN_DEBUG
++ "%02X:%02X:%02X:%02X:%02X:%02X \n",
++ spydata->spy_address[i][0],
++ spydata->spy_address[i][1],
++ spydata->spy_address[i][2],
++ spydata->spy_address[i][3],
++ spydata->spy_address[i][4],
++ spydata->spy_address[i][5]);
++#endif /* WE_SPY_DEBUG */
++ }
++ /* Enable addresses */
++ spydata->spy_number = wrqu->data.length;
++
++ return 0;
++#else /* IW_WIRELESS_SPY */
++ return -EOPNOTSUPP;
++#endif /* IW_WIRELESS_SPY */
++}
++
++/*------------------------------------------------------------------*/
++/*
++ * Standard Wireless Handler : get Spy List
++ */
++int iw_handler_get_spy(struct net_device * dev,
++ struct iw_request_info * info,
++ union iwreq_data * wrqu,
++ char * extra)
++{
++#ifdef IW_WIRELESS_SPY
++ struct iw_spy_data * spydata = (dev->priv +
++ dev->wireless_handlers->spy_offset);
++ struct sockaddr * address = (struct sockaddr *) extra;
++ int i;
++
++ wrqu->data.length = spydata->spy_number;
++
++ /* Copy addresses. */
++ for(i = 0; i < spydata->spy_number; i++) {
++ memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
++ address[i].sa_family = AF_UNIX;
++ }
++ /* Copy stats to the user buffer (just after). */
++ if(spydata->spy_number > 0)
++ memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
++ spydata->spy_stat,
++ sizeof(struct iw_quality) * spydata->spy_number);
++ /* Reset updated flags. */
++ for(i = 0; i < spydata->spy_number; i++)
++ spydata->spy_stat[i].updated = 0;
++ return 0;
++#else /* IW_WIRELESS_SPY */
++ return -EOPNOTSUPP;
++#endif /* IW_WIRELESS_SPY */
++}
++
++/*------------------------------------------------------------------*/
++/*
++ * Standard Wireless Handler : set spy threshold
++ */
++int iw_handler_set_thrspy(struct net_device * dev,
++ struct iw_request_info *info,
++ union iwreq_data * wrqu,
++ char * extra)
++{
++#ifdef IW_WIRELESS_THRSPY
++ struct iw_spy_data * spydata = (dev->priv +
++ dev->wireless_handlers->spy_offset);
++ struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
++
++ /* Just do it */
++ memcpy(&(spydata->spy_thr_low), &(threshold->low),
++ 2 * sizeof(struct iw_quality));
++
++ /* Clear flag */
++ memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
++
++#ifdef WE_SPY_DEBUG
++ printk(KERN_DEBUG "iw_handler_set_thrspy() : low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level);
++#endif /* WE_SPY_DEBUG */
++
++ return 0;
++#else /* IW_WIRELESS_THRSPY */
++ return -EOPNOTSUPP;
++#endif /* IW_WIRELESS_THRSPY */
++}
++
++/*------------------------------------------------------------------*/
++/*
++ * Standard Wireless Handler : get spy threshold
++ */
++int iw_handler_get_thrspy(struct net_device * dev,
++ struct iw_request_info *info,
++ union iwreq_data * wrqu,
++ char * extra)
++{
++#ifdef IW_WIRELESS_THRSPY
++ struct iw_spy_data * spydata = (dev->priv +
++ dev->wireless_handlers->spy_offset);
++ struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
++
++ /* Just do it */
++ memcpy(&(threshold->low), &(spydata->spy_thr_low),
++ 2 * sizeof(struct iw_quality));
++
++ return 0;
++#else /* IW_WIRELESS_THRSPY */
++ return -EOPNOTSUPP;
++#endif /* IW_WIRELESS_THRSPY */
++}
++
++#ifdef IW_WIRELESS_THRSPY
++/*------------------------------------------------------------------*/
++/*
++ * Prepare and send a Spy Threshold event
++ */
++static void iw_send_thrspy_event(struct net_device * dev,
++ struct iw_spy_data * spydata,
++ unsigned char * address,
++ struct iw_quality * wstats)
++{
++ union iwreq_data wrqu;
++ struct iw_thrspy threshold;
++
++ /* Init */
++ wrqu.data.length = 1;
++ wrqu.data.flags = 0;
++ /* Copy address */
++ memcpy(threshold.addr.sa_data, address, ETH_ALEN);
++ threshold.addr.sa_family = ARPHRD_ETHER;
++ /* Copy stats */
++ memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
++ /* Copy also thresholds */
++ memcpy(&(threshold.low), &(spydata->spy_thr_low),
++ 2 * sizeof(struct iw_quality));
++
++#ifdef WE_SPY_DEBUG
++ printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n",
++ threshold.addr.sa_data[0],
++ threshold.addr.sa_data[1],
++ threshold.addr.sa_data[2],
++ threshold.addr.sa_data[3],
++ threshold.addr.sa_data[4],
++ threshold.addr.sa_data[5], threshold.qual.level);
++#endif /* WE_SPY_DEBUG */
++
++ /* Send event to user space */
++ wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
++}
++#endif /* IW_WIRELESS_THRSPY */
++
++/* ---------------------------------------------------------------- */
++/*
++ * Call for the driver to update the spy data.
++ * For now, the spy data is a simple array. As the size of the array is
++ * small, this is good enough. If we wanted to support larger number of
++ * spy addresses, we should use something more efficient...
++ */
++void wireless_spy_update(struct net_device * dev,
++ unsigned char * address,
++ struct iw_quality * wstats)
++{
++#ifdef IW_WIRELESS_SPY
++ struct iw_spy_data * spydata = (dev->priv +
++ dev->wireless_handlers->spy_offset);
++ int i;
++ int match = -1;
++
++#ifdef WE_SPY_DEBUG
++ printk(KERN_DEBUG "wireless_spy_update() : offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
++#endif /* WE_SPY_DEBUG */
++
++ /* Update all records that match */
++ for(i = 0; i < spydata->spy_number; i++)
++ if(!memcmp(address, spydata->spy_address[i], ETH_ALEN)) {
++ memcpy(&(spydata->spy_stat[i]), wstats,
++ sizeof(struct iw_quality));
++ match = i;
++ }
++#ifdef IW_WIRELESS_THRSPY
++ /* Generate an event if we cross the spy threshold.
++ * To avoid event storms, we have a simple hysteresis : we generate
++ * event only when we go under the low threshold or above the
++ * high threshold. */
++ if(match >= 0) {
++ if(spydata->spy_thr_under[match]) {
++ if(wstats->level > spydata->spy_thr_high.level) {
++ spydata->spy_thr_under[match] = 0;
++ iw_send_thrspy_event(dev, spydata,
++ address, wstats);
++ }
++ } else {
++ if(wstats->level < spydata->spy_thr_low.level) {
++ spydata->spy_thr_under[match] = 1;
++ iw_send_thrspy_event(dev, spydata,
++ address, wstats);
++ }
++ }
++ }
++#endif /* IW_WIRELESS_THRSPY */
++#endif /* IW_WIRELESS_SPY */
+ }
+--- linux-2.4.21/net/ipv4/ipconfig.c~net-dhcp-timeout
++++ linux-2.4.21/net/ipv4/ipconfig.c
+@@ -87,7 +87,7 @@
+
+ /* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */
+ #define CONF_OPEN_RETRIES 2 /* (Re)open devices twice */
+-#define CONF_SEND_RETRIES 6 /* Send six requests per open */
++#define CONF_SEND_RETRIES 4 /* Send six requests per open */
+ #define CONF_INTER_TIMEOUT (HZ/2) /* Inter-device timeout: 1/2 second */
+ #define CONF_BASE_TIMEOUT (HZ*2) /* Initial timeout: 2 seconds */
+ #define CONF_TIMEOUT_RANDOM (HZ) /* Maximum amount of randomization */
+@@ -1238,9 +1238,11 @@
+ #endif
+
+ if (--retries) {
++#ifndef CONFIG_ARCH_RAMSES
+ printk(KERN_ERR
+ "IP-Config: Reopening network devices...\n");
+ goto try_try_again;
++#endif
+ }
+
+ /* Oh, well. At least we tried. */
+--- linux-2.4.21/net/netsyms.c~linux-iw241_we16-6
++++ linux-2.4.21/net/netsyms.c
+@@ -601,6 +601,11 @@
+ #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
+ #include <net/iw_handler.h>
+ EXPORT_SYMBOL(wireless_send_event);
++EXPORT_SYMBOL(iw_handler_set_spy);
++EXPORT_SYMBOL(iw_handler_get_spy);
++EXPORT_SYMBOL(iw_handler_set_thrspy);
++EXPORT_SYMBOL(iw_handler_get_thrspy);
++EXPORT_SYMBOL(wireless_spy_update);
+ #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
+
+ #endif /* CONFIG_NET */
diff --git a/linux/mnci-ramses_2.4.21-rmk2-pxa1.oe b/linux/mnci-ramses_2.4.21-rmk2-pxa1.oe
index 143bc71659..198ba2dcca 100644
--- a/linux/mnci-ramses_2.4.21-rmk2-pxa1.oe
+++ b/linux/mnci-ramses_2.4.21-rmk2-pxa1.oe
@@ -4,7 +4,7 @@ LICENSE = "GPL"
KV = "2.4.21"
RMKV = "2"
PXAV = "1"
-#PR = "r0"
+PR = "r1"
SRC_URI = "ftp://ftp.kernel.org/pub/linux/kernel/v2.4/linux-${KV}.tar.bz2 \
ftp://ftp.arm.linux.org.uk/pub/armlinux/source/kernel-patches/v2.4/patch-${KV}-rmk${RMKV}.gz;patch=1 \
@@ -62,3 +62,15 @@ kernel_do_install() {
bzip2 -9 ${D}/boot/*
install -d ${D}/etc/modutils
}
+
+do_stage () {
+ rm -rf ${STAGING_INCDIR}/linux ${STAGING_INCDIR}/asm
+ mkdir -p ${STAGING_INCDIR}/linux ${STAGING_INCDIR}/asm
+ cp -a include/linux/* ${STAGING_INCDIR}/linux/
+ cp -a include/asm/* ${STAGING_INCDIR}/asm/
+ find ${STAGING_INCDIR}/linux -name "*~*" | xargs rm
+ find ${STAGING_INCDIR}/asm -name "*~*" | xargs rm
+
+ ln -sf ${STAGING_KERNEL_DIR}/include/linux/wireless.h ${STAGING_INCDIR}/linux/wireless.h
+ ln -sf ${STAGING_KERNEL_DIR}/include/linux/wireless.h ${CROSS_DIR}/${TARGET_SYS}/include/linux/wireless.h
+}