summaryrefslogtreecommitdiff
path: root/recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-vrs1-pxa1.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-vrs1-pxa1.patch')
-rw-r--r--recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-vrs1-pxa1.patch40457
1 files changed, 40457 insertions, 0 deletions
diff --git a/recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-vrs1-pxa1.patch b/recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-vrs1-pxa1.patch
new file mode 100644
index 0000000000..7c1252e93c
--- /dev/null
+++ b/recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-vrs1-pxa1.patch
@@ -0,0 +1,40457 @@
+
+#
+# Patch managed by http://www.holgerschurig.de/patcher.html
+#
+
+--- linux-2.4.27/Documentation/Configure.help~2.4.27-vrs1-pxa1
++++ linux-2.4.27/Documentation/Configure.help
+@@ -4630,6 +4630,24 @@
+ building a kernel for install/rescue disks or your system is very
+ limited in memory.
+
++Kernel Execute-In-Place from ROM
++CONFIG_XIP_KERNEL
++ Execute-In-Place allows the kernel to run directly from
++ non-volatile storage, such as flash. This saves RAM space since
++ the text section of the kernel is not loaded from flash to
++ RAM. Read-write sections, such as the data section and stack,
++ are still copied to RAM. The XIP kernel is not compressed since it
++ has to run directly from flash, so it will take more space to store
++ it. The flash address where the kernel is linked to run from and
++ is stored is board dependent. Therefore, if you say Y, you must
++ know the proper physical address where to store the kernel image.
++
++ Also note that the make target becomes "make xipImage" rather than
++ "make zImage" or "make Image". The final kernel binary to put in
++ ROM memory will be arch/arm/boot/xipImage.
++
++ If unsure, say N.
++
+ # Choice: kcore
+ Kernel core (/proc/kcore) format
+ CONFIG_KCORE_ELF
+@@ -13609,6 +13627,30 @@
+
+ If you don't know what this all is, saying Y is a safe choice.
+
++Workaround for XScale cache errata
++CONFIG_XSCALE_CACHE_ERRATA
++ There are couple errata that say that the cache may get confused
++ whether some cache lines are dirty or not, resulting in some memory
++ corruptions. The workaround (using the cache only in write through
++ mode) is performance impairing, and the bug _might_ just not be
++ that visible or critical to you depending on many esoteric
++ hardware factors.
++
++ Not using the workaround makes Linux unreliable. If you're used
++ to some other OSes which requires to be rebooted once in a while
++ then this won't look so bad to you. On the other hand you may
++ stress test the system for hours without seeing any effect of this
++ bug.
++
++ So this is configurable. Let's hope a future core revision will tell
++ this was just a bad dream. But in the mean time the risk and
++ trade-off is yours to decide.
++
++ This should apply to all PXA250 up to rev B2 (erratum #120) and
++ possibly other current XScale cores as well.
++
++ If you don't know what to answer, say Y.
++
+ Support CD-ROM drives that are not SCSI or IDE/ATAPI
+ CONFIG_CD_NO_IDESCSI
+ If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y
+@@ -16812,6 +16854,40 @@
+
+ If unsure, say N.
+
++Use linear addressing for cramfs
++CONFIG_CRAMFS_LINEAR
++ This option tells the cramfs driver to load data directly from a linear
++ adressed memory range (usually non volatile memory like flash) instead
++ of going through the block device layer. This saves some memory since
++ no intermediate buffering is necessary.
++
++ This is also a prerequisite for XIP of binaries stored on the filesystem.
++
++ The location of the cramfs image in memory is board dependent. Therefore,
++ if you say Y, you must know the proper physical address where to store
++ the cramfs image and specify it using the physaddr=0x******** mount
++ option (for example: "mount -t cramfs -o physaddr=0x100000 none /mnt").
++
++ If unsure, say N.
++
++Support XIP on linear cramfs
++CONFIG_CRAMFS_LINEAR_XIP
++ You must say Y to this option if you want to be able to run applications
++ directly from non-volatile memory. XIP applications are marked by
++ setting the sticky bit (ie, "chmod +t <app name>"). A cramfs file system
++ then needs to be created using mkcramfs (with XIP cramfs support
++ in it). Applications marked for XIP execution will not be compressed
++ since they have to run directly from flash.
++
++Root file system on linear cramfs
++CONFIG_ROOT_CRAMFS_LINEAR
++ Say Y if you have enabled linear cramfs, and you want to be able to use
++ the linear cramfs image as a root file system. To actually have the
++ kernel mount this cramfs image as a root file system, you must also pass
++ the command line parameter "root=/dev/null rootflags=physaddr=0x********"
++ to the kernel (replace 0x******** with the physical address location
++ of the linear cramfs image to boot with).
++
+ CMS file system support
+ CONFIG_CMS_FS
+ Read only support for CMS minidisk file systems found on IBM
+--- /dev/null
++++ linux-2.4.27/Documentation/arm/XScale/PXA/USB-client
+@@ -0,0 +1,38 @@
++Date: Wed, 05 Jun 2002 13:38:53 -0700
++From: Frank Becker <fbecker@intrinsyc.com>
++To: Nicolas Pitre <nico@cam.org>
++Subject: [PATCH] PXA-USB
++
++Hi Nicolas,
++
++one more patch...
++
++This patch adds minimal USB client (UDC) support.
++
++Some notes:
++It adds just enough to get usb-eth working. I.e.
++endpoints 0-2, no dma. Performance isn't stellar
++partially due to UDC bug workarounds...
++(~350K @ 100Mhz, ~550K @ 200Mhz).
++
++Endpoint 1&2 have changed direction compared to
++the SA, so the host side requires a change to
++usbnet.c to flip endpoints (in:2/out:1 -> in:1/out:2).
++
++usb-eth and usb-char for PXA are almost identical
++to the SA versions, so they could probably be merged at
++one point. I made some minor changes to the eth driver
++to grab the usb resources at open, rather than at init
++and allow eth&char to be loaded at the same time.
++
++Stuart Lynne was working on his own USB client driver
++(and he was getting higher throughput than my driver).
++Assuming you guys have something in the oven for USB
++as well, there should be good selection for best of
++breed :)
++
++Cheers,
++Frank.
++--
++Frank Becker - Intrinsyc Software, Inc. - http://www.intrinsyc.com/
++Need a break? http://criticalmass.sf.net/
+--- linux-2.4.27/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/Makefile
+@@ -1,7 +1,7 @@
+ VERSION = 2
+ PATCHLEVEL = 4
+ SUBLEVEL = 27
+-EXTRAVERSION = -vrs1
++EXTRAVERSION =-vrs1-pxa1
+
+ KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+
+@@ -167,6 +167,7 @@
+ DRIVERS-$(CONFIG_SOUND) += drivers/sound/sounddrivers.o
+ DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o
+ DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o
++DRIVERS-$(CONFIG_MMC) += drivers/mmc/mmcdrivers.o
+ DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmcia/pcmcia.o
+ DRIVERS-$(CONFIG_NET_PCMCIA) += drivers/net/pcmcia/pcmcia_net.o
+ DRIVERS-$(CONFIG_NET_WIRELESS) += drivers/net/wireless/wireless_net.o
+--- linux-2.4.27/arch/arm/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/Makefile
+@@ -13,10 +13,11 @@
+ CFLAGS +=-Uarm -fno-common -pipe
+
+ ifeq ($(CONFIG_FRAME_POINTER),y)
+-CFLAGS :=$(CFLAGS:-fomit-frame-pointer=-mapcs -mno-sched-prolog)
++CFLAGS :=$(CFLAGS:-fomit-frame-pointer=)
++CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog
+ endif
+
+-CFLAGS :=$(CFLAGS:-O2=-Os)
++#CFLAGS :=$(CFLAGS:-O2=-Os)
+
+ ifeq ($(CONFIG_DEBUG_INFO),y)
+ CFLAGS +=-g
+@@ -38,6 +39,8 @@
+ arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3
+ arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4
+ arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 -march=armv5
++#arch-$(CONFIG_CPU_XSCALE) :=-D__LINUX_ARM_ARCH__=5 -mcpu=xscale
++arch-$(CONFIG_CPU_XSCALE) :=-D__LINUX_ARM_ARCH__=5 -march=armv4 -Wa,-mxscale
+
+ # This selects how we optimise for the processor.
+ tune-y :=
+@@ -49,6 +52,8 @@
+ tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi
+ tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110
+ tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100
++#tune-$(CONFIG_CPU_XSCALE) :=-mtune=xscale
++tune-$(CONFIG_CPU_XSCALE) :=-mtune=strongarm
+
+ CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
+ CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
+@@ -127,6 +132,10 @@
+ MACHINE = sa1100
+ endif
+
++ifeq ($(CONFIG_ARCH_PXA),y)
++MACHINE = pxa
++endif
++
+ ifeq ($(CONFIG_ARCH_L7200),y)
+ MACHINE = l7200
+ endif
+@@ -164,6 +173,17 @@
+ MACHINE = omaha
+ endif
+
++ifeq ($(CONFIG_XIP_KERNEL),y)
++ DATAADDR := $(TEXTADDR)
++ # Replace phys addr with virt addr while keeping offset from base.
++ # Virt base addr also defined in include/asm-arm/arch-*/hardware.h
++ TEXTADDR = $(shell echo 0x`echo $(CONFIG_XIP_PHYS_ADDR)|sed -e's/^0x//'` |\
++ awk --non-decimal-data '/[:xdigit:]/ \
++ {printf("0x%x\n",and($$0,0x001fffff)+0xe8000000)}' )
++ LDSCRIPT = arch/arm/vmlinux-armv-xip.lds.in
++ export DATAADDR
++endif
++
+ export MACHINE PROCESSOR TEXTADDR GZFLAGS CFLAGS_BOOT OBJCOPYFLAGS
+
+ # Only set INCDIR if its not already defined above
+@@ -269,7 +289,7 @@
+ arch/arm/kernel arch/arm/mm arch/arm/lib: dummy
+ $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)
+
+-bzImage zImage zinstall Image bootpImage install: vmlinux
++bzImage zImage zinstall Image xipImage bootpImage install: vmlinux
+ @$(MAKEBOOT) $@
+
+ CLEAN_FILES += \
+--- linux-2.4.27/arch/arm/boot/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/boot/Makefile
+@@ -113,6 +113,10 @@
+ endif
+ endif
+
++ifeq ($(CONFIG_ARCH_PXA),y)
++ZRELADDR = 0xa0008000
++endif
++
+ ifeq ($(CONFIG_ARCH_ANAKIN),y)
+ ZRELADDR = 0x20008000
+ endif
+@@ -140,6 +144,14 @@
+ zImage: compressed/vmlinux
+ $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
+
++ifeq ($(CONFIG_XIP_KERNEL),y)
++xipImage: $(CONFIGURE) $(SYSTEM)
++ $(OBJCOPY) -S -O binary -R .data $(SYSTEM) vmlinux-text.bin
++ $(OBJCOPY) -S -O binary -R .init -R .text -R __ex_table -R __ksymtab $(SYSTEM) vmlinux-data.bin
++ cat vmlinux-text.bin vmlinux-data.bin > $@
++ $(RM) -f vmlinux-text.bin vmlinux-data.bin
++endif
++
+ bootpImage: bootp/bootp
+ $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
+
+@@ -160,7 +172,7 @@
+ sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
+
+ clean:
+- $(RM) Image zImage bootpImage
++ $(RM) Image xipImage zImage bootpImage
+ @$(MAKE) -C compressed clean
+ @$(MAKE) -C bootp clean
+
+--- linux-2.4.27/arch/arm/boot/compressed/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/boot/compressed/Makefile
+@@ -71,6 +71,10 @@
+ OBJS += head-sa1100.o
+ endif
+
++ifeq ($(CONFIG_CPU_XSCALE),y)
++OBJS += head-xscale.o
++endif
++
+ SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$(ZBSSADDR)/
+
+ LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
+--- /dev/null
++++ linux-2.4.27/arch/arm/boot/compressed/head-xscale.S
+@@ -0,0 +1,50 @@
++/*
++ * linux/arch/arm/boot/compressed/head-xscale.S
++ *
++ * XScale specific tweaks. This is merged into head.S by the linker.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/linkage.h>
++#include <asm/mach-types.h>
++
++ .section ".start", #alloc, #execinstr
++
++__XScale_start:
++
++ @ Preserve r8/r7 i.e. kernel entry values
++
++ @ Data cache might be active.
++ @ Be sure to flush kernel binary out of the cache,
++ @ whatever state it is, before it is turned off.
++ @ This is done by fetching through currently executed
++ @ memory to be sure we hit the same cache.
++ bic r2, pc, #0x1f
++ add r3, r2, #0x10000 @ 64 kb is quite enough...
++1: ldr r0, [r2], #32
++ teq r2, r3
++ bne 1b
++ mcr p15, 0, r0, c7, c10, 4 @ drain WB
++ mcr p15, 0, r0, c7, c7, 0 @ flush I & D caches
++
++ @ disabling MMU and caches
++ mrc p15, 0, r0, c1, c0, 0 @ read control reg
++ bic r0, r0, #0x05 @ clear DC, MMU
++ bic r0, r0, #0x1000 @ clear Icache
++ mcr p15, 0, r0, c1, c0, 0
++
++#ifdef CONFIG_ARCH_LUBBOCK
++ mov r7, #MACH_TYPE_LUBBOCK
++#endif
++
++#ifdef CONFIG_ARCH_PXA_IDP
++ mov r7, #MACH_TYPE_PXA_IDP
++#endif
++
++#ifdef CONFIG_ARCH_TRIZEPS2
++ mov r7, #(MACH_TYPE_TRIZEPS2 & 0xFF00)
++ add r7, r7, #(MACH_TYPE_TRIZEPS2 & 0xFF)
++#endif
++
++
+--- linux-2.4.27/arch/arm/boot/compressed/head.S~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/boot/compressed/head.S
+@@ -351,7 +351,11 @@
+ orr r1, r1, #3 << 10
+ add r2, r3, #16384
+ 1: cmp r1, r8 @ if virt > start of RAM
++#ifdef CONFIG_XSCALE_CACHE_ERRATA
++ orrhs r1, r1, #0x08 @ set cacheable, not bufferable
++#else
+ orrhs r1, r1, #0x0c @ set cacheable, bufferable
++#endif
+ cmp r1, r9 @ if virt > end of RAM
+ bichs r1, r1, #0x0c @ clear cacheable, bufferable
+ str r1, [r0], #4 @ 1:1 mapping
+@@ -364,7 +368,11 @@
+ * so there is no map overlap problem for up to 1 MB compressed kernel.
+ * If the execution is in RAM then we would only be duplicating the above.
+ */
++#ifdef CONFIG_XSCALE_CACHE_ERRATA
++ mov r1, #0x1a
++#else
+ mov r1, #0x1e
++#endif
+ orr r1, r1, #3 << 10
+ mov r2, pc, lsr #20
+ orr r1, r1, r2, lsl #20
+--- linux-2.4.27/arch/arm/config.in~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/config.in
+@@ -38,6 +38,7 @@
+ Cirrus-CL-PS7500FE CONFIG_ARCH_CLPS7500 \
+ CLPS711x/EP721x-based CONFIG_ARCH_CLPS711X \
+ Co-EBSA285 CONFIG_ARCH_CO285 \
++ PXA250/210-based CONFIG_ARCH_PXA \
+ EBSA-110 CONFIG_ARCH_EBSA110 \
+ Excalibur-ARM CONFIG_ARCH_CAMELOT \
+ FootBridge CONFIG_ARCH_FOOTBRIDGE \
+@@ -148,6 +149,47 @@
+ endmenu
+
+ mainmenu_option next_comment
++comment 'Intel PXA250/210 Implementations'
++dep_bool ' Intel DBPXA250 Development Platform' CONFIG_ARCH_LUBBOCK $CONFIG_ARCH_PXA
++dep_bool ' Accelent Xscale IDP' CONFIG_ARCH_PXA_IDP $CONFIG_ARCH_PXA
++dep_bool ' Intrinsyc CerfBoard' CONFIG_ARCH_PXA_CERF $CONFIG_ARCH_PXA
++dep_bool ' Trizeps-II MT6N' CONFIG_ARCH_TRIZEPS2 $CONFIG_ARCH_PXA
++
++if [ "$CONFIG_ARCH_PXA_CERF" = "y" ]; then
++ define_bool CONFIG_PXA_CERF y
++
++ choice 'CerfBoard Style' \
++ "PDA CONFIG_PXA_CERF_PDA \
++ BOARD CONFIG_PXA_CERF_BOARD" PDA
++
++ choice 'CerfBoard RAM Available' \
++ "128MB CONFIG_PXA_CERF_RAM_128MB \
++ 64MB CONFIG_PXA_CERF_RAM_64MB \
++ 32MB CONFIG_PXA_CERF_RAM_32MB \
++ 16MB CONFIG_PXA_CERF_RAM_16MB" 64MB
++
++ choice 'CerfBoard Flash Available' \
++ "64MB CONFIG_PXA_CERF_FLASH_64MB \
++ 32MB CONFIG_PXA_CERF_FLASH_32MB \
++ 16MB CONFIG_PXA_CERF_FLASH_16MB \
++ 8MB CONFIG_PXA_CERF_FLASH_8MB" 32MB
++fi
++
++if [ "$CONFIG_ARCH_LUBBOCK" = "y" ]; then
++ define_bool CONFIG_SA1111 y
++fi
++
++if [ "$CONFIG_ARCH_TRIZEPS2" = "y" ]; then
++ define_bool CONFIG_TRIZEPS2 y
++fi
++
++dep_tristate 'PXA USB function support' CONFIG_PXA_USB $CONFIG_ARCH_PXA
++dep_tristate ' Support for PXA USB network link function' CONFIG_PXA_USB_NETLINK $CONFIG_PXA_USB
++dep_tristate ' Support for PXA USB character device emulation' CONFIG_PXA_USB_CHAR $CONFIG_PXA_USB
++
++endmenu
++
++mainmenu_option next_comment
+ comment 'CLPS711X/EP721X Implementations'
+ dep_bool ' AUTCPU12' CONFIG_ARCH_AUTCPU12 $CONFIG_ARCH_CLPS711X
+ dep_bool ' CDB89712' CONFIG_ARCH_CDB89712 $CONFIG_ARCH_CLPS711X
+@@ -385,6 +427,12 @@
+ define_bool CONFIG_CPU_SA1100 n
+ fi
+
++if [ "$CONFIG_ARCH_PXA" = "y" ]; then
++ define_bool CONFIG_CPU_32v5 y
++ define_bool CONFIG_CPU_XSCALE y
++ bool 'Workaround for XScale cache errata (see help)' CONFIG_XSCALE_CACHE_ERRATA
++fi
++
+ # Figure out what processor architecture version we should be using.
+ # This defines the compiler instruction set which depends on the machine type.
+
+@@ -493,6 +541,7 @@
+ hex 'Compressed ROM boot loader BSS address' CONFIG_ZBOOT_ROM_BSS 0
+
+ if [ "$CONFIG_ARCH_SA1100" = "y" -o \
++ "$CONFIG_ARCH_PXA" = "y" -o \
+ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
+ dep_bool 'Support CPU clock change (EXPERIMENTAL)' CONFIG_CPU_FREQ $CONFIG_EXPERIMENTAL
+ fi
+@@ -501,8 +550,10 @@
+ bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+ if [ "$CONFIG_HOTPLUG" = "y" ]; then
+ source drivers/pcmcia/Config.in
++ source drivers/mmc/Config.in
+ else
+ define_bool CONFIG_PCMCIA n
++ define_bool CONFIG_MMC n
+ fi
+ if [ "$CONFIG_SA1100_ACCELENT" = "y" ]; then
+ if [ "$CONFIG_PCMCIA" != "n" ]; then
+@@ -513,6 +564,14 @@
+ bool 'System V IPC' CONFIG_SYSVIPC
+ bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+ bool 'Sysctl support' CONFIG_SYSCTL
++
++if [ "$CONFIG_ARCH_PXA" = "y" ]; then
++ dep_bool 'Kernel Execute-In-Place from ROM (EXPERIMENTAL)' CONFIG_XIP_KERNEL $CONFIG_EXPERIMENTAL
++ if [ "$CONFIG_XIP_KERNEL" = "y" ]; then
++ hex ' Kernel .text physical address' CONFIG_XIP_PHYS_ADDR 0
++ fi
++fi
++
+ comment 'At least one math emulation must be selected'
+ tristate 'NWFPE math emulation' CONFIG_FPE_NWFPE
+ if [ "$CONFIG_FPE_NWFPE" != "n" ]; then
+@@ -538,6 +597,9 @@
+ "$CONFIG_ARCH_SHARK" = "y" -o \
+ "$CONFIG_ARCH_CO285" = "y" -o \
+ "$CONFIG_ARCH_SA1100" = "y" -o \
++ "$CONFIG_ARCH_LUBBOCK" = "y" -o \
++ "$CONFIG_ARCH_PXA_IDP" = "y" -o \
++ "$CONFIG_ARCH_PXA_CERF" = "y" -o \
+ "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
+ "$CONFIG_ARCH_CDB89712" = "y" -o \
+ "$CONFIG_ARCH_P720T" = "y" -o \
+@@ -550,9 +612,12 @@
+ "$CONFIG_ARCH_SHARK" = "y" -o \
+ "$CONFIG_ARCH_CO285" = "y" -o \
+ "$CONFIG_ARCH_SA1100" = "y" -o \
++ "$CONFIG_ARCH_LUBBOCK" = "y" -o \
+ "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
+ "$CONFIG_ARCH_P720T" = "y" -o \
+ "$CONFIG_ARCH_OMAHA" = "y" -o \
++ "$CONFIG_ARCH_PXA_CERF" = "y" -o \
++ "$CONFIG_ARCH_PXA_IDP" = "y" -o \
+ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then
+ bool ' Timer LED' CONFIG_LEDS_TIMER
+ bool ' CPU usage LED' CONFIG_LEDS_CPU
+@@ -686,6 +751,7 @@
+ if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \
+ "$CONFIG_ARCH_SHARK" = "y" -o \
+ "$CONFIG_ARCH_SA1100" = "y" -o \
++ "$CONFIG_ARCH_PXA" = "y" -o \
+ "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
+ "$CONFIG_ARCH_TBOX" = "y" -o \
+ "$CONFIG_ARCH_CLPS7500" = "y" -o \
+@@ -707,6 +773,7 @@
+ "$CONFIG_ARCH_TBOX" = "y" -o \
+ "$CONFIG_ARCH_SHARK" = "y" -o \
+ "$CONFIG_ARCH_SA1100" = "y" -o \
++ "$CONFIG_ARCH_PXA" = "y" -o \
+ "$CONFIG_PCI" = "y" ]; then
+ mainmenu_option next_comment
+ comment 'Sound'
+--- /dev/null
++++ linux-2.4.27/arch/arm/def-configs/cerfboard_pxa
+@@ -0,0 +1,857 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_H3600_SLEEVE is not set
++
++#
++# Intel PXA250/210 Implementations
++#
++# CONFIG_ARCH_LUBBOCK is not set
++# CONFIG_ARCH_PXA_IDP is not set
++CONFIG_ARCH_PXA_CERF=y
++CONFIG_PXA_CERF=y
++# CONFIG_PXA_CERF_PDA is not set
++CONFIG_PXA_CERF_BOARD=y
++# CONFIG_PXA_CERF_RAM_128MB is not set
++CONFIG_PXA_CERF_RAM_64MB=y
++# CONFIG_PXA_CERF_RAM_32MB is not set
++# CONFIG_PXA_CERF_RAM_16MB is not set
++# CONFIG_PXA_CERF_FLASH_64MB is not set
++CONFIG_PXA_CERF_FLASH_32MB=y
++# CONFIG_PXA_CERF_FLASH_16MB is not set
++# CONFIG_PXA_CERF_FLASH_8MB is not set
++CONFIG_PXA_USB=y
++CONFIG_PXA_USB_NETLINK=y
++CONFIG_PXA_USB_CHAR=m
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++CONFIG_XSCALE_CACHE_ERRATA=y
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_CPU_FREQ=y
++CONFIG_HOTPLUG=y
++
++#
++# PCMCIA/CardBus support
++#
++CONFIG_PCMCIA=y
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++# CONFIG_TCIC is not set
++# CONFIG_PCMCIA_CLPS6700 is not set
++# CONFIG_PCMCIA_SA1100 is not set
++CONFIG_PCMCIA_PXA=y
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_SYSCTL=y
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_PM is not set
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="root=1f03 rw console=tty0 console=ttyS0,38400 init=/linuxrc"
++CONFIG_LEDS=y
++# CONFIG_LEDS_TIMER is not set
++CONFIG_LEDS_CPU=y
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_REDBOOT_PARTS=y
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++CONFIG_MTD_CFI_ADV_OPTIONS=y
++CONFIG_MTD_CFI_NOSWAP=y
++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
++CONFIG_MTD_CFI_GEOMETRY=y
++# CONFIG_MTD_CFI_B1 is not set
++# CONFIG_MTD_CFI_B2 is not set
++CONFIG_MTD_CFI_B4=y
++# CONFIG_MTD_CFI_B8 is not set
++# CONFIG_MTD_CFI_I1 is not set
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_LUBBOCK is not set
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_FORTUNET is not set
++CONFIG_MTD_PXA_CERF=y
++# CONFIG_MTD_EPXA10DB is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_PCI is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++CONFIG_BLK_DEV_LOOP=m
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_INITRD=y
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++CONFIG_FILTER=y
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_ARM_CIRRUS is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++CONFIG_NET_VENDOR_SMC=y
++# CONFIG_WD80x3 is not set
++# CONFIG_ULTRAMCA is not set
++# CONFIG_ULTRA is not set
++# CONFIG_ULTRA32 is not set
++# CONFIG_SMC9194 is not set
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++CONFIG_PPP=m
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPP_FILTER is not set
++CONFIG_PPP_ASYNC=m
++# CONFIG_PPP_SYNC_TTY is not set
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_BSDCOMP=m
++# CONFIG_PPPOE is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# PCMCIA network device support
++#
++CONFIG_NET_PCMCIA=y
++CONFIG_PCMCIA_3C589=m
++CONFIG_PCMCIA_3C574=m
++CONFIG_PCMCIA_FMVJ18X=m
++CONFIG_PCMCIA_PCNET=m
++CONFIG_PCMCIA_AXNET=m
++CONFIG_PCMCIA_NMCLAN=m
++CONFIG_PCMCIA_SMC91C92=m
++CONFIG_PCMCIA_XIRC2PS=m
++# CONFIG_ARCNET_COM20020_CS is not set
++# CONFIG_PCMCIA_IBMTR is not set
++CONFIG_NET_PCMCIA_RADIO=y
++CONFIG_PCMCIA_RAYCS=m
++CONFIG_PCMCIA_NETWAVE=m
++CONFIG_PCMCIA_WAVELAN=m
++CONFIG_AIRONET4500_CS=m
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++# CONFIG_BLK_DEV_HD_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++CONFIG_BLK_DEV_IDEDISK=y
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_IDEDISK_STROKE is not set
++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
++# CONFIG_BLK_DEV_IDEDISK_IBM is not set
++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
++# CONFIG_BLK_DEV_IDEDISK_WD is not set
++# CONFIG_BLK_DEV_COMMERIAL is not set
++# CONFIG_BLK_DEV_TIVO is not set
++CONFIG_BLK_DEV_IDECS=m
++# CONFIG_BLK_DEV_IDECD is not set
++# CONFIG_BLK_DEV_IDETAPE is not set
++# CONFIG_BLK_DEV_IDEFLOPPY is not set
++# CONFIG_BLK_DEV_IDESCSI is not set
++# CONFIG_IDE_TASK_IOCTL is not set
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_IDE_MODES is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++# CONFIG_INPUT is not set
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++CONFIG_I2C_PXA_ALGO=y
++CONFIG_I2C_PXA_ADAP=y
++# CONFIG_I2C_CHARDEV is not set
++# CONFIG_I2C_PROC is not set
++# CONFIG_I2C_DS1307 is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_QIC02_TAPE is not set
++
++#
++# Watchdog Cards
++#
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++# CONFIG_ACQUIRE_WDT is not set
++# CONFIG_ADVANTECH_WDT is not set
++# CONFIG_ALIM7101_WDT is not set
++# CONFIG_SC520_WDT is not set
++# CONFIG_PCWATCHDOG is not set
++# CONFIG_21285_WATCHDOG is not set
++# CONFIG_977_WATCHDOG is not set
++# CONFIG_SA1100_WATCHDOG is not set
++CONFIG_PXA_WATCHDOG=m
++# CONFIG_OMAHA_WATCHDOG is not set
++# CONFIG_EUROTECH_WDT is not set
++# CONFIG_IB700_WDT is not set
++# CONFIG_WAFER_WDT is not set
++# CONFIG_I810_TCO is not set
++# CONFIG_MIXCOMWD is not set
++# CONFIG_60XX_WDT is not set
++# CONFIG_SC1200_WDT is not set
++# CONFIG_SOFT_WATCHDOG is not set
++# CONFIG_W83877F_WDT is not set
++# CONFIG_WDT is not set
++# CONFIG_WDTPCI is not set
++# CONFIG_MACHZ_WDT is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_PXA_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# PCMCIA character devices
++#
++CONFIG_PCMCIA_SERIAL_CS=y
++CONFIG_PCMCIA_CHRDEV=y
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++CONFIG_UMSDOS_FS=m
++CONFIG_VFAT_FS=m
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_CRAMFS is not set
++CONFIG_TMPFS=y
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++# CONFIG_DEVFS_FS is not set
++# CONFIG_DEVFS_MOUNT is not set
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++CONFIG_ROMFS_FS=y
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++# CONFIG_ZLIB_FS_INFLATE is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=m
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++CONFIG_NLS_CODEPAGE_850=m
++CONFIG_NLS_CODEPAGE_852=m
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++CONFIG_NLS_CODEPAGE_863=m
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ISO8859_1=m
++CONFIG_NLS_ISO8859_2=m
++CONFIG_NLS_ISO8859_3=m
++CONFIG_NLS_ISO8859_4=m
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Console drivers
++#
++CONFIG_PC_KEYMAP=y
++# CONFIG_VGA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++# CONFIG_FB is not set
++
++#
++# Sound
++#
++# CONFIG_SOUND is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++# CONFIG_MCP_UCB1400_TS is not set
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SLAB is not set
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_WAITQ is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
+--- /dev/null
++++ linux-2.4.27/arch/arm/def-configs/cerfpda_pxa
+@@ -0,0 +1,962 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_H3600_SLEEVE is not set
++
++#
++# Intel PXA250/210 Implementations
++#
++# CONFIG_ARCH_LUBBOCK is not set
++# CONFIG_ARCH_PXA_IDP is not set
++CONFIG_ARCH_PXA_CERF=y
++CONFIG_PXA_CERF=y
++CONFIG_PXA_CERF_PDA=y
++# CONFIG_PXA_CERF_BOARD is not set
++# CONFIG_PXA_CERF_RAM_128MB is not set
++CONFIG_PXA_CERF_RAM_64MB=y
++# CONFIG_PXA_CERF_RAM_32MB is not set
++# CONFIG_PXA_CERF_RAM_16MB is not set
++# CONFIG_PXA_CERF_FLASH_64MB is not set
++CONFIG_PXA_CERF_FLASH_32MB=y
++# CONFIG_PXA_CERF_FLASH_16MB is not set
++# CONFIG_PXA_CERF_FLASH_8MB is not set
++CONFIG_PXA_USB=y
++CONFIG_PXA_USB_NETLINK=y
++CONFIG_PXA_USB_CHAR=y
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++# CONFIG_XSCALE_CACHE_ERRATA is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_HOTPLUG=y
++
++#
++# PCMCIA/CardBus support
++#
++CONFIG_PCMCIA=y
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++# CONFIG_TCIC is not set
++# CONFIG_PCMCIA_CLPS6700 is not set
++# CONFIG_PCMCIA_SA1100 is not set
++CONFIG_PCMCIA_PXA=y
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_SYSCTL=y
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_PM is not set
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="root=1f03 rw console=tty0 console=ttyS0,38400 init=/linuxrc"
++CONFIG_LEDS=y
++# CONFIG_LEDS_TIMER is not set
++CONFIG_LEDS_CPU=y
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_REDBOOT_PARTS=y
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++CONFIG_MTD_CFI_ADV_OPTIONS=y
++CONFIG_MTD_CFI_NOSWAP=y
++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
++CONFIG_MTD_CFI_GEOMETRY=y
++# CONFIG_MTD_CFI_B1 is not set
++# CONFIG_MTD_CFI_B2 is not set
++CONFIG_MTD_CFI_B4=y
++# CONFIG_MTD_CFI_B8 is not set
++# CONFIG_MTD_CFI_I1 is not set
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_LUBBOCK is not set
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_FORTUNET is not set
++CONFIG_MTD_PXA_CERF=y
++# CONFIG_MTD_EPXA10DB is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_PCI is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++CONFIG_BLK_DEV_LOOP=m
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_INITRD=y
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++CONFIG_FILTER=y
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++# CONFIG_NET_VENDOR_SMC is not set
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++CONFIG_PPP=m
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPP_FILTER is not set
++CONFIG_PPP_ASYNC=m
++# CONFIG_PPP_SYNC_TTY is not set
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_BSDCOMP=m
++# CONFIG_PPPOE is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# PCMCIA network device support
++#
++CONFIG_NET_PCMCIA=y
++CONFIG_PCMCIA_3C589=m
++CONFIG_PCMCIA_3C574=m
++CONFIG_PCMCIA_FMVJ18X=m
++CONFIG_PCMCIA_PCNET=m
++CONFIG_PCMCIA_AXNET=m
++CONFIG_PCMCIA_NMCLAN=m
++CONFIG_PCMCIA_SMC91C92=m
++CONFIG_PCMCIA_XIRC2PS=m
++# CONFIG_ARCNET_COM20020_CS is not set
++# CONFIG_PCMCIA_IBMTR is not set
++# CONFIG_NET_PCMCIA_RADIO is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++CONFIG_IRDA=y
++CONFIG_IRLAN=y
++# CONFIG_IRNET is not set
++CONFIG_IRCOMM=y
++CONFIG_IRDA_ULTRA=y
++# CONFIG_IRDA_CACHE_LAST_LSAP is not set
++# CONFIG_IRDA_FAST_RR is not set
++CONFIG_IRDA_DEBUG=y
++
++#
++# Infrared-port device drivers
++#
++CONFIG_IRTTY_SIR=y
++# CONFIG_IRPORT_SIR is not set
++# CONFIG_DONGLE is not set
++# CONFIG_USB_IRDA is not set
++# CONFIG_NSC_FIR is not set
++# CONFIG_WINBOND_FIR is not set
++# CONFIG_TOSHIBA_FIR is not set
++# CONFIG_SMC_IRCC_FIR is not set
++# CONFIG_ALI_FIR is not set
++# CONFIG_VLSI_FIR is not set
++
++#
++# ATA/IDE/MFM/RLL support
++#
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++# CONFIG_BLK_DEV_HD_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++CONFIG_BLK_DEV_IDEDISK=y
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
++# CONFIG_BLK_DEV_IDEDISK_IBM is not set
++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
++# CONFIG_BLK_DEV_IDEDISK_WD is not set
++# CONFIG_BLK_DEV_COMMERIAL is not set
++# CONFIG_BLK_DEV_TIVO is not set
++CONFIG_BLK_DEV_IDECS=m
++# CONFIG_BLK_DEV_IDECD is not set
++# CONFIG_BLK_DEV_IDETAPE is not set
++# CONFIG_BLK_DEV_IDEFLOPPY is not set
++# CONFIG_BLK_DEV_IDESCSI is not set
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_IDE_MODES is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_INPUT_NS558 is not set
++# CONFIG_INPUT_LIGHTNING is not set
++# CONFIG_INPUT_PCIGAME is not set
++# CONFIG_INPUT_CS461X is not set
++# CONFIG_INPUT_EMU10K1 is not set
++# CONFIG_INPUT_SERIO is not set
++# CONFIG_INPUT_SERPORT is not set
++# CONFIG_INPUT_ANALOG is not set
++# CONFIG_INPUT_A3D is not set
++# CONFIG_INPUT_ADI is not set
++# CONFIG_INPUT_COBRA is not set
++# CONFIG_INPUT_GF2K is not set
++# CONFIG_INPUT_GRIP is not set
++# CONFIG_INPUT_INTERACT is not set
++# CONFIG_INPUT_TMDC is not set
++# CONFIG_INPUT_SIDEWINDER is not set
++# CONFIG_INPUT_IFORCE_USB is not set
++# CONFIG_INPUT_IFORCE_232 is not set
++# CONFIG_INPUT_WARRIOR is not set
++# CONFIG_INPUT_MAGELLAN is not set
++# CONFIG_INPUT_SPACEORB is not set
++# CONFIG_INPUT_SPACEBALL is not set
++# CONFIG_INPUT_STINGER is not set
++# CONFIG_INPUT_DB9 is not set
++# CONFIG_INPUT_GAMECON is not set
++# CONFIG_INPUT_TURBOGRAFX is not set
++# CONFIG_QIC02_TAPE is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_INTEL_RNG is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# PCMCIA character devices
++#
++CONFIG_PCMCIA_SERIAL_CS=y
++CONFIG_PCMCIA_CHRDEV=y
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++CONFIG_UMSDOS_FS=m
++CONFIG_VFAT_FS=m
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_CRAMFS is not set
++CONFIG_TMPFS=y
++CONFIG_RAMFS=m
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++# CONFIG_DEVFS_FS is not set
++# CONFIG_DEVFS_MOUNT is not set
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++CONFIG_ROMFS_FS=y
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++# CONFIG_ZLIB_FS_INFLATE is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=m
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++CONFIG_NLS_CODEPAGE_850=m
++CONFIG_NLS_CODEPAGE_852=m
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++CONFIG_NLS_CODEPAGE_863=m
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ISO8859_1=m
++CONFIG_NLS_ISO8859_2=m
++CONFIG_NLS_ISO8859_3=m
++CONFIG_NLS_ISO8859_4=m
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Console drivers
++#
++CONFIG_PC_KEYMAP=y
++# CONFIG_VGA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++CONFIG_FB=y
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FB_ACORN is not set
++# CONFIG_FB_ANAKIN is not set
++# CONFIG_FB_CLPS711X is not set
++# CONFIG_FB_SA1100 is not set
++CONFIG_FB_PXA=y
++# CONFIG_FB_PXA_8BPP is not set
++CONFIG_FB_PXA_16BPP=y
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FBCON_ADVANCED is not set
++CONFIG_FBCON_CFB2=y
++CONFIG_FBCON_CFB4=y
++CONFIG_FBCON_CFB8=y
++CONFIG_FBCON_CFB16=y
++# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
++CONFIG_FBCON_FONTS=y
++# CONFIG_FONT_8x8 is not set
++# CONFIG_FONT_8x16 is not set
++# CONFIG_FONT_SUN8x16 is not set
++# CONFIG_FONT_SUN12x22 is not set
++# CONFIG_FONT_6x11 is not set
++# CONFIG_FONT_PEARL_8x8 is not set
++CONFIG_FONT_ACORN_8x8=y
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_CMPCI is not set
++# CONFIG_SOUND_EMU10K1 is not set
++# CONFIG_MIDI_EMU10K1 is not set
++# CONFIG_SOUND_FUSION is not set
++# CONFIG_SOUND_CS4281 is not set
++# CONFIG_SOUND_ES1370 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ESSSOLO1 is not set
++# CONFIG_SOUND_MAESTRO is not set
++# CONFIG_SOUND_MAESTRO3 is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_RME96XX is not set
++# CONFIG_SOUND_SONICVIBES is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_MIDI_VIA82CXXX is not set
++# CONFIG_SOUND_OSS is not set
++# CONFIG_SOUND_WAVEARTIST is not set
++CONFIG_SOUND_PXA_AC97=y
++# CONFIG_SOUND_TVMIXER is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++CONFIG_MCP_UCB1400_TS=y
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++# CONFIG_USB_UHCI is not set
++# CONFIG_USB_UHCI_ALT is not set
++# CONFIG_USB_OHCI is not set
++# CONFIG_USB_OHCI_SA1111 is not set
++# CONFIG_USB_AUDIO is not set
++# CONFIG_USB_BLUETOOTH is not set
++# CONFIG_USB_STORAGE is not set
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_DPCM is not set
++# CONFIG_USB_STORAGE_HP8200e is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_HID is not set
++# CONFIG_USB_HIDDEV is not set
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++# CONFIG_USB_WACOM is not set
++# CONFIG_USB_DC2XX is not set
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_SCANNER is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USB_HPUSBSCSI is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_CDCETHER is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_USS720 is not set
++
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
++# CONFIG_USB_SERIAL_GENERIC is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_PL2303 is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_RIO500 is not set
++
++#
++# Bluetooth support
++#
++CONFIG_BLUEZ=y
++CONFIG_BLUEZ_L2CAP=y
++
++#
++# Bluetooth device drivers
++#
++# CONFIG_BLUEZ_HCIUSB is not set
++CONFIG_BLUEZ_HCIUART=y
++CONFIG_BLUEZ_HCIVHCI=y
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SLAB is not set
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_WAITQ is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
+--- /dev/null
++++ linux-2.4.27/arch/arm/def-configs/csb226
+@@ -0,0 +1,615 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_AT91RM9200DK is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_HACKKIT is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_H3600_SLEEVE is not set
++
++#
++# Intel PXA250/210 Board
++#
++# CONFIG_ARCH_PXA_IDP is not set
++# CONFIG_ARCH_INNOKOM is not set
++CONFIG_ARCH_CSB226=y
++# CONFIG_ARCH_LUBBOCK is not set
++# CONFIG_ARCH_PXA_CERF is not set
++# CONFIG_PXA_USB is not set
++# CONFIG_PXA_USB_NETLINK is not set
++# CONFIG_PXA_USB_CHAR is not set
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++CONFIG_XSCALE_CACHE_ERRATA=y
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++# CONFIG_CPU_FREQ is not set
++# CONFIG_HOTPLUG is not set
++# CONFIG_PCMCIA is not set
++# CONFIG_MMC is not set
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++# CONFIG_XIP_KERNEL is not set
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_PM is not set
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="console=ttyS0,19200"
++CONFIG_ALIGNMENT_TRAP=y
++CONFIG_ARM_HWTIMER=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++# CONFIG_MTD is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_LOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++# CONFIG_PACKET is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++CONFIG_ARM_CIRRUS=y
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++# CONFIG_NET_VENDOR_SMC is not set
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++# CONFIG_BLK_DEV_IDE_MODES is not set
++# CONFIG_BLK_DEV_HD is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++# CONFIG_INPUT is not set
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_QIC02_TAPE is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_PXA_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++# CONFIG_JBD_DEBUG is not set
++# CONFIG_FAT_FS is not set
++# CONFIG_MSDOS_FS is not set
++# CONFIG_UMSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++# CONFIG_JFFS2_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_TMPFS is not set
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++# CONFIG_DEVFS_FS is not set
++# CONFIG_DEVFS_MOUNT is not set
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_EXT2_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++# CONFIG_NFS_V3 is not set
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++# CONFIG_ZLIB_FS_INFLATE is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++# CONFIG_MSDOS_PARTITION is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_SMB_NLS is not set
++# CONFIG_NLS is not set
++
++#
++# Sound
++#
++# CONFIG_SOUND is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++# CONFIG_MCP_UCB1400_TS is not set
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++CONFIG_DEBUG_SLAB=y
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_DEBUG_SPINLOCK=y
++CONFIG_DEBUG_WAITQ=y
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
+--- /dev/null
++++ linux-2.4.27/arch/arm/def-configs/innokom
+@@ -0,0 +1,699 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_AT91RM9200DK is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_HACKKIT is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_H3600_SLEEVE is not set
++
++#
++# Intel PXA250/210 Board
++#
++# CONFIG_ARCH_PXA_IDP is not set
++CONFIG_ARCH_INNOKOM=y
++# CONFIG_ARCH_CSB226 is not set
++# CONFIG_ARCH_LUBBOCK is not set
++# CONFIG_ARCH_PXA_CERF is not set
++# CONFIG_PXA_USB is not set
++# CONFIG_PXA_USB_NETLINK is not set
++# CONFIG_PXA_USB_CHAR is not set
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++CONFIG_XSCALE_CACHE_ERRATA=y
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++# CONFIG_CPU_FREQ is not set
++# CONFIG_HOTPLUG is not set
++# CONFIG_PCMCIA is not set
++# CONFIG_MMC is not set
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++# CONFIG_XIP_KERNEL is not set
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_PM is not set
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="root=/dev/nfs mem=32M ip=dhcp console=ttyS0,19200"
++CONFIG_ALIGNMENT_TRAP=y
++CONFIG_ARM_HWTIMER=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_CONCAT is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_CFI_INTELEXT=y
++CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_CFI_STAA is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_LUBBOCK is not set
++# CONFIG_MTD_EPXA10DB is not set
++# CONFIG_MTD_FORTUNET is not set
++CONFIG_MTD_INNOKOM=y
++CONFIG_MTD_INNOKOM_16MB=y
++# CONFIG_MTD_INNOKOM_64MB is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_CEIVA is not set
++# CONFIG_MTD_PCI is not set
++# CONFIG_MTD_PCMCIA is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_LOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++# CONFIG_PACKET is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++# CONFIG_IP_PNP_BOOTP is not set
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_ARM_CIRRUS is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++CONFIG_NET_VENDOR_SMC=y
++# CONFIG_WD80x3 is not set
++# CONFIG_ULTRAMCA is not set
++# CONFIG_ULTRA is not set
++# CONFIG_ULTRA32 is not set
++# CONFIG_SMC9194 is not set
++CONFIG_SMC91X=y
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++# CONFIG_BLK_DEV_IDE_MODES is not set
++# CONFIG_BLK_DEV_HD is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++# CONFIG_INPUT is not set
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++CONFIG_I2C_PXA_ALGO=y
++CONFIG_I2C_PXA_ADAP=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_PROC=y
++# CONFIG_I2C_DS1307 is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_QIC02_TAPE is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_PXA_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++# CONFIG_JBD_DEBUG is not set
++# CONFIG_FAT_FS is not set
++# CONFIG_MSDOS_FS is not set
++# CONFIG_UMSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_JFFS2_FS_NAND is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_TMPFS is not set
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_EXT2_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++# CONFIG_ZLIB_FS_INFLATE is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++# CONFIG_MSDOS_PARTITION is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_SMB_NLS is not set
++# CONFIG_NLS is not set
++
++#
++# Sound
++#
++# CONFIG_SOUND is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++# CONFIG_MCP_UCB1400_TS is not set
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++CONFIG_DEBUG_SLAB=y
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_DEBUG_SPINLOCK=y
++CONFIG_DEBUG_WAITQ=y
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
+--- /dev/null
++++ linux-2.4.27/arch/arm/def-configs/lubbock
+@@ -0,0 +1,971 @@
++#
++# Automatically generated make config: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++# CONFIG_KMOD is not set
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_AT91RM9200 is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++
++#
++# Archimedes/A5000 Implementations (select only ONE)
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSAGC is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_ADSBITSYPLUS is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_H3600_SLEEVE is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_HACKKIT is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_SA1100_SSP is not set
++
++#
++# AT91RM9200 Implementations
++#
++# CONFIG_ARCH_AT91RM9200DK is not set
++
++#
++# Intel PXA250/210 Implementations
++#
++CONFIG_ARCH_LUBBOCK=y
++# CONFIG_ARCH_PXA_IDP is not set
++# CONFIG_ARCH_PXA_CERF is not set
++# CONFIG_ARCH_TRIZEPS2 is not set
++CONFIG_SA1111=y
++# CONFIG_PXA_USB is not set
++# CONFIG_PXA_USB_NETLINK is not set
++# CONFIG_PXA_USB_CHAR is not set
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_GUIDEA07 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++# CONFIG_XSCALE_CACHE_ERRATA is not set
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++
++#
++# Processor Features
++#
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_CPU_FREQ=y
++CONFIG_HOTPLUG=y
++
++#
++# PCMCIA/CardBus support
++#
++CONFIG_PCMCIA=y
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++# CONFIG_TCIC is not set
++# CONFIG_PCMCIA_CLPS6700 is not set
++# CONFIG_PCMCIA_SA1100 is not set
++CONFIG_PCMCIA_PXA=y
++
++#
++# MMC device drivers
++#
++CONFIG_MMC=m
++CONFIG_MMC_PXA=m
++CONFIG_MMC_BLOCK=m
++CONFIG_MMC_PARTITIONS=y
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++# CONFIG_XIP_KERNEL is not set
++
++#
++# At least one math emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++CONFIG_PM=y
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=32M"
++CONFIG_LEDS=y
++CONFIG_LEDS_TIMER=y
++CONFIG_LEDS_CPU=y
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_REDBOOT_PARTS=y
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++CONFIG_MTD_CFI_ADV_OPTIONS=y
++CONFIG_MTD_CFI_NOSWAP=y
++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
++CONFIG_MTD_CFI_GEOMETRY=y
++# CONFIG_MTD_CFI_B1 is not set
++CONFIG_MTD_CFI_B2=y
++CONFIG_MTD_CFI_B4=y
++# CONFIG_MTD_CFI_B8 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_CFI_STAA is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++CONFIG_MTD_LUBBOCK=y
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_FORTUNET is not set
++# CONFIG_MTD_EPXA is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_CEIVA is not set
++# CONFIG_MTD_PCI is not set
++# CONFIG_MTD_PCMCIA is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_LOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_BLK_STATS is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++# CONFIG_PACKET is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++
++#
++#
++#
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_ARM_CIRRUS is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++CONFIG_NET_VENDOR_SMC=y
++# CONFIG_WD80x3 is not set
++# CONFIG_ULTRAMCA is not set
++# CONFIG_ULTRA is not set
++# CONFIG_ULTRA32 is not set
++# CONFIG_SMC9194 is not set
++CONFIG_SMC91X=y
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_E1000 is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_R8169 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# PCMCIA network device support
++#
++CONFIG_NET_PCMCIA=y
++# CONFIG_PCMCIA_3C589 is not set
++# CONFIG_PCMCIA_3C574 is not set
++# CONFIG_PCMCIA_FMVJ18X is not set
++CONFIG_PCMCIA_PCNET=y
++# CONFIG_PCMCIA_AXNET is not set
++# CONFIG_PCMCIA_NMCLAN is not set
++# CONFIG_PCMCIA_SMC91C92 is not set
++# CONFIG_PCMCIA_XIRC2PS is not set
++# CONFIG_ARCNET_COM20020_CS is not set
++# CONFIG_PCMCIA_IBMTR is not set
++# CONFIG_NET_PCMCIA_RADIO is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++
++#
++# Please see Documentation/ide.txt for help/info on IDE drives
++#
++# CONFIG_BLK_DEV_HD_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++CONFIG_BLK_DEV_IDEDISK=y
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_IDEDISK_STROKE is not set
++CONFIG_BLK_DEV_IDECS=y
++# CONFIG_BLK_DEV_IDECD is not set
++# CONFIG_BLK_DEV_IDETAPE is not set
++# CONFIG_BLK_DEV_IDEFLOPPY is not set
++# CONFIG_BLK_DEV_IDESCSI is not set
++# CONFIG_IDE_TASK_IOCTL is not set
++
++#
++# IDE chipset support/bugfixes
++#
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++CONFIG_BLK_DEV_IDE_MODES=y
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++# CONFIG_BLK_DEV_ATARAID_SII is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_MX1TS is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++# CONFIG_VT_CONSOLE is not set
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++# CONFIG_SERIAL_AT91 is not set
++# CONFIG_SERIAL_AT91_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++
++#
++# Other L3 adapters
++#
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++CONFIG_BUSMOUSE=y
++# CONFIG_ATIXL_BUSMOUSE is not set
++# CONFIG_LOGIBUSMOUSE is not set
++# CONFIG_MS_BUSMOUSE is not set
++CONFIG_MOUSE=y
++CONFIG_PSMOUSE=y
++# CONFIG_82C710_MOUSE is not set
++# CONFIG_PC110_PAD is not set
++# CONFIG_MK712_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_INPUT_NS558 is not set
++# CONFIG_INPUT_LIGHTNING is not set
++# CONFIG_INPUT_PCIGAME is not set
++# CONFIG_INPUT_CS461X is not set
++# CONFIG_INPUT_EMU10K1 is not set
++# CONFIG_INPUT_SERIO is not set
++# CONFIG_INPUT_SERPORT is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_ANALOG is not set
++# CONFIG_INPUT_A3D is not set
++# CONFIG_INPUT_ADI is not set
++# CONFIG_INPUT_COBRA is not set
++# CONFIG_INPUT_GF2K is not set
++# CONFIG_INPUT_GRIP is not set
++# CONFIG_INPUT_INTERACT is not set
++# CONFIG_INPUT_TMDC is not set
++# CONFIG_INPUT_SIDEWINDER is not set
++# CONFIG_INPUT_IFORCE_USB is not set
++# CONFIG_INPUT_IFORCE_232 is not set
++# CONFIG_INPUT_WARRIOR is not set
++# CONFIG_INPUT_MAGELLAN is not set
++# CONFIG_INPUT_SPACEORB is not set
++# CONFIG_INPUT_SPACEBALL is not set
++# CONFIG_INPUT_STINGER is not set
++# CONFIG_INPUT_DB9 is not set
++# CONFIG_INPUT_GAMECON is not set
++# CONFIG_INPUT_TURBOGRAFX is not set
++# CONFIG_QIC02_TAPE is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_IPMI_PANIC_EVENT is not set
++# CONFIG_IPMI_DEVICE_INTERFACE is not set
++# CONFIG_IPMI_KCS is not set
++# CONFIG_IPMI_WATCHDOG is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_SCx200_GPIO is not set
++# CONFIG_AMD_PM768 is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++CONFIG_PXA_RTC=y
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# PCMCIA character devices
++#
++# CONFIG_PCMCIA_SERIAL_CS is not set
++# CONFIG_SYNCLINK_CS is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BEFS_DEBUG is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++# CONFIG_UMSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_CRAMFS is not set
++# CONFIG_CRAMFS_LINEAR is not set
++# CONFIG_CRAMFS_LINEAR_XIP is not set
++# CONFIG_ROOT_CRAMFS_LINEAR is not set
++# CONFIG_TMPFS is not set
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_JFS_DEBUG is not set
++# CONFIG_JFS_STATISTICS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++# CONFIG_NFS_V3 is not set
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++# CONFIG_NFSD_TCP is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++# CONFIG_NLS_CODEPAGE_437 is not set
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Console drivers
++#
++CONFIG_PC_KEYMAP=y
++# CONFIG_VGA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++CONFIG_FB=y
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FB_ACORN is not set
++# CONFIG_FB_ANAKIN is not set
++# CONFIG_FB_CLPS711X is not set
++# CONFIG_FB_SA1100 is not set
++# CONFIG_FB_DBMX1 is not set
++CONFIG_FB_PXA=y
++# CONFIG_FB_PXA_8BPP is not set
++CONFIG_FB_PXA_16BPP=y
++# CONFIG_FB_PXA_QVGA is not set
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FBCON_ADVANCED is not set
++CONFIG_FBCON_CFB2=y
++CONFIG_FBCON_CFB4=y
++CONFIG_FBCON_CFB8=y
++CONFIG_FBCON_CFB16=y
++CONFIG_FBCON_FONTWIDTH8_ONLY=y
++# CONFIG_FBCON_FONTS is not set
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++# CONFIG_SOUND_ALI5455 is not set
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_CMPCI is not set
++# CONFIG_SOUND_EMU10K1 is not set
++# CONFIG_MIDI_EMU10K1 is not set
++# CONFIG_SOUND_FUSION is not set
++# CONFIG_SOUND_CS4281 is not set
++# CONFIG_SOUND_ES1370 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ESSSOLO1 is not set
++# CONFIG_SOUND_MAESTRO is not set
++# CONFIG_SOUND_MAESTRO3 is not set
++# CONFIG_SOUND_FORTE is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_RME96XX is not set
++# CONFIG_SOUND_SONICVIBES is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_MIDI_VIA82CXXX is not set
++# CONFIG_SOUND_OSS is not set
++# CONFIG_SOUND_VIDC is not set
++# CONFIG_SOUND_WAVEARTIST is not set
++CONFIG_SOUND_PXA_AC97=y
++# CONFIG_SOUND_TVMIXER is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++CONFIG_MCP_UCB1400_TS=y
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SLAB is not set
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_WAITQ is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
++
++#
++# Library routines
++#
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
+--- /dev/null
++++ linux-2.4.27/arch/arm/def-configs/pxa_idp
+@@ -0,0 +1,933 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_H3600_SLEEVE is not set
++
++#
++# Intel PXA250/210 Implementations
++#
++# CONFIG_ARCH_LUBBOCK is not set
++CONFIG_ARCH_PXA_IDP=y
++# CONFIG_ARCH_PXA_CERF is not set
++CONFIG_PXA_USB=m
++CONFIG_PXA_USB_NETLINK=m
++CONFIG_PXA_USB_CHAR=m
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++# CONFIG_XSCALE_CACHE_ERRATA is not set
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_HOTPLUG=y
++
++#
++# PCMCIA/CardBus support
++#
++CONFIG_PCMCIA=y
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++# CONFIG_TCIC is not set
++# CONFIG_PCMCIA_CLPS6700 is not set
++# CONFIG_PCMCIA_SA1100 is not set
++CONFIG_PCMCIA_PXA=y
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++CONFIG_PM=y
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="root=/dev/mtdblock2 init=/linuxrc console=ttyS0,115200"
++CONFIG_LEDS=y
++CONFIG_LEDS_TIMER=y
++CONFIG_LEDS_CPU=y
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_CONCAT is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++CONFIG_MTD_CFI_ADV_OPTIONS=y
++CONFIG_MTD_CFI_NOSWAP=y
++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
++CONFIG_MTD_CFI_GEOMETRY=y
++# CONFIG_MTD_CFI_B1 is not set
++# CONFIG_MTD_CFI_B2 is not set
++CONFIG_MTD_CFI_B4=y
++# CONFIG_MTD_CFI_B8 is not set
++# CONFIG_MTD_CFI_I1 is not set
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++CONFIG_MTD_LUBBOCK=y
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_FORTUNET is not set
++# CONFIG_MTD_PXA_CERF is not set
++# CONFIG_MTD_EPXA10DB is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++CONFIG_ASI_MTD0_SIZE=40000
++CONFIG_ASI_MTD1_SIZE=100000
++CONFIG_ASI_MTD2_SIZE=1e00000
++# CONFIG_MTD_PCI is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_INITRD=y
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_ARM_CIRRUS is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++CONFIG_NET_VENDOR_SMC=y
++# CONFIG_WD80x3 is not set
++# CONFIG_ULTRAMCA is not set
++# CONFIG_ULTRA is not set
++# CONFIG_ULTRA32 is not set
++# CONFIG_SMC9194 is not set
++CONFIG_SMC91111=m
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++CONFIG_NET_POCKET=y
++# CONFIG_DE600 is not set
++# CONFIG_DE620 is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++CONFIG_NET_RADIO=y
++# CONFIG_STRIP is not set
++CONFIG_WAVELAN=m
++# CONFIG_ARLAN is not set
++CONFIG_AIRONET4500=y
++# CONFIG_AIRONET4500_NONCS is not set
++# CONFIG_AIRONET4500_PROC is not set
++CONFIG_HERMES=m
++CONFIG_PCMCIA_HERMES=m
++CONFIG_AIRO_CS=m
++CONFIG_NET_WIRELESS=y
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# PCMCIA network device support
++#
++CONFIG_NET_PCMCIA=y
++# CONFIG_PCMCIA_3C589 is not set
++# CONFIG_PCMCIA_3C574 is not set
++# CONFIG_PCMCIA_FMVJ18X is not set
++CONFIG_PCMCIA_PCNET=m
++# CONFIG_PCMCIA_AXNET is not set
++CONFIG_PCMCIA_NMCLAN=m
++CONFIG_PCMCIA_SMC91C92=m
++CONFIG_PCMCIA_XIRC2PS=m
++# CONFIG_ARCNET_COM20020_CS is not set
++# CONFIG_PCMCIA_IBMTR is not set
++CONFIG_NET_PCMCIA_RADIO=y
++CONFIG_PCMCIA_RAYCS=m
++CONFIG_PCMCIA_NETWAVE=m
++CONFIG_PCMCIA_WAVELAN=m
++CONFIG_AIRONET4500_CS=m
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++CONFIG_IRDA=m
++CONFIG_IRLAN=m
++# CONFIG_IRNET is not set
++CONFIG_IRCOMM=m
++CONFIG_IRDA_ULTRA=y
++# CONFIG_IRDA_CACHE_LAST_LSAP is not set
++# CONFIG_IRDA_FAST_RR is not set
++CONFIG_IRDA_DEBUG=y
++
++#
++# Infrared-port device drivers
++#
++CONFIG_IRTTY_SIR=m
++# CONFIG_IRPORT_SIR is not set
++# CONFIG_DONGLE is not set
++# CONFIG_USB_IRDA is not set
++# CONFIG_NSC_FIR is not set
++# CONFIG_WINBOND_FIR is not set
++# CONFIG_TOSHIBA_FIR is not set
++# CONFIG_SMC_IRCC_FIR is not set
++# CONFIG_ALI_FIR is not set
++# CONFIG_VLSI_FIR is not set
++CONFIG_PXA_FIR=m
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++# CONFIG_BLK_DEV_HD_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++CONFIG_BLK_DEV_IDEDISK=y
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_IDEDISK_STROKE is not set
++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
++# CONFIG_BLK_DEV_IDEDISK_IBM is not set
++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
++# CONFIG_BLK_DEV_IDEDISK_WD is not set
++# CONFIG_BLK_DEV_COMMERIAL is not set
++# CONFIG_BLK_DEV_TIVO is not set
++CONFIG_BLK_DEV_IDECS=m
++# CONFIG_BLK_DEV_IDECD is not set
++# CONFIG_BLK_DEV_IDETAPE is not set
++# CONFIG_BLK_DEV_IDEFLOPPY is not set
++# CONFIG_BLK_DEV_IDESCSI is not set
++# CONFIG_IDE_TASK_IOCTL is not set
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_IDE_MODES is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_KEYBDEV=m
++CONFIG_INPUT_MOUSEDEV=m
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++
++#
++# Character devices
++#
++CONFIG_VT=y
++# CONFIG_VT_CONSOLE is not set
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++# CONFIG_IDP_KEYB is not set
++CONFIG_MATRIX_KEYBOARD=y
++# CONFIG_SA1111_PS2_KEYB is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++CONFIG_BUSMOUSE=y
++# CONFIG_ATIXL_BUSMOUSE is not set
++# CONFIG_LOGIBUSMOUSE is not set
++# CONFIG_MS_BUSMOUSE is not set
++CONFIG_MOUSE=y
++CONFIG_PSMOUSE=y
++# CONFIG_82C710_MOUSE is not set
++# CONFIG_PC110_PAD is not set
++# CONFIG_MK712_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_INPUT_NS558 is not set
++# CONFIG_INPUT_LIGHTNING is not set
++# CONFIG_INPUT_PCIGAME is not set
++# CONFIG_INPUT_CS461X is not set
++# CONFIG_INPUT_EMU10K1 is not set
++# CONFIG_INPUT_SERIO is not set
++# CONFIG_INPUT_SERPORT is not set
++# CONFIG_INPUT_ANALOG is not set
++# CONFIG_INPUT_A3D is not set
++# CONFIG_INPUT_ADI is not set
++# CONFIG_INPUT_COBRA is not set
++# CONFIG_INPUT_GF2K is not set
++# CONFIG_INPUT_GRIP is not set
++# CONFIG_INPUT_INTERACT is not set
++# CONFIG_INPUT_TMDC is not set
++# CONFIG_INPUT_SIDEWINDER is not set
++# CONFIG_INPUT_IFORCE_USB is not set
++# CONFIG_INPUT_IFORCE_232 is not set
++# CONFIG_INPUT_WARRIOR is not set
++# CONFIG_INPUT_MAGELLAN is not set
++# CONFIG_INPUT_SPACEORB is not set
++# CONFIG_INPUT_SPACEBALL is not set
++# CONFIG_INPUT_STINGER is not set
++# CONFIG_INPUT_DB9 is not set
++# CONFIG_INPUT_GAMECON is not set
++# CONFIG_INPUT_TURBOGRAFX is not set
++# CONFIG_QIC02_TAPE is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_PXA_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# PCMCIA character devices
++#
++CONFIG_PCMCIA_SERIAL_CS=m
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++CONFIG_EXT3_FS=m
++CONFIG_JBD=m
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++# CONFIG_UMSDOS_FS is not set
++CONFIG_VFAT_FS=m
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_CRAMFS=y
++# CONFIG_TMPFS is not set
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++CONFIG_ZLIB_FS_INFLATE=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=m
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Console drivers
++#
++CONFIG_PC_KEYMAP=y
++# CONFIG_VGA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++CONFIG_FB=y
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FB_ACORN is not set
++# CONFIG_FB_ANAKIN is not set
++# CONFIG_FB_CLPS711X is not set
++# CONFIG_FB_SA1100 is not set
++CONFIG_FB_PXA=y
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FBCON_ADVANCED is not set
++CONFIG_FBCON_CFB2=y
++CONFIG_FBCON_CFB4=y
++CONFIG_FBCON_CFB8=y
++CONFIG_FBCON_CFB16=y
++# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
++# CONFIG_FBCON_FONTS is not set
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_CMPCI is not set
++# CONFIG_SOUND_EMU10K1 is not set
++# CONFIG_MIDI_EMU10K1 is not set
++# CONFIG_SOUND_FUSION is not set
++# CONFIG_SOUND_CS4281 is not set
++# CONFIG_SOUND_ES1370 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ESSSOLO1 is not set
++# CONFIG_SOUND_MAESTRO is not set
++# CONFIG_SOUND_MAESTRO3 is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_RME96XX is not set
++# CONFIG_SOUND_SONICVIBES is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_MIDI_VIA82CXXX is not set
++# CONFIG_SOUND_OSS is not set
++# CONFIG_SOUND_WAVEARTIST is not set
++CONFIG_SOUND_PXA_AC97=y
++# CONFIG_SOUND_TVMIXER is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++CONFIG_MCP_UCB1400_TS=m
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++CONFIG_DEBUG_SLAB=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_WAITQ is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++# CONFIG_DEBUG_LL is not set
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
+--- /dev/null
++++ linux-2.4.27/arch/arm/def-configs/trizeps2
+@@ -0,0 +1,873 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_H3600_SLEEVE is not set
++
++#
++# Intel PXA250/210 Implementations
++#
++# CONFIG_ARCH_LUBBOCK is not set
++# CONFIG_ARCH_PXA_IDP is not set
++# CONFIG_ARCH_PXA_CERF is not set
++CONFIG_ARCH_TRIZEPS2=y
++CONFIG_TRIZEPS2=y
++CONFIG_PXA_USB=y
++# CONFIG_PXA_USB_NETLINK is not set
++# CONFIG_PXA_USB_CHAR is not set
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++# CONFIG_XSCALE_CACHE_ERRATA is not set
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_HOTPLUG=y
++
++#
++# PCMCIA/CardBus support
++#
++CONFIG_PCMCIA=y
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++# CONFIG_TCIC is not set
++# CONFIG_PCMCIA_CLPS6700 is not set
++# CONFIG_PCMCIA_SA1100 is not set
++CONFIG_PCMCIA_PXA=y
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_PM is not set
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="root=/dev/mtdblock3 rw console=ttyS0,38400 mem=32M noinitrd init=/linuxrc"
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_REDBOOT_PARTS=y
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_LUBBOCK is not set
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_FORTUNET is not set
++# CONFIG_MTD_PXA_CERF is not set
++# CONFIG_MTD_EPXA10DB is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++CONFIG_MTD_TRIZEPS2=y
++# CONFIG_MTD_PCI is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++# CONFIG_PACKET is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_ARM_CIRRUS is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++CONFIG_NET_VENDOR_SMC=y
++# CONFIG_WD80x3 is not set
++# CONFIG_ULTRAMCA is not set
++# CONFIG_ULTRA is not set
++# CONFIG_ULTRA32 is not set
++CONFIG_SMC9194=y
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++CONFIG_PPP=m
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPP_FILTER is not set
++CONFIG_PPP_ASYNC=m
++CONFIG_PPP_SYNC_TTY=m
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_BSDCOMP=m
++# CONFIG_PPPOE is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++CONFIG_NET_RADIO=y
++# CONFIG_STRIP is not set
++# CONFIG_WAVELAN is not set
++# CONFIG_ARLAN is not set
++# CONFIG_AIRONET4500 is not set
++# CONFIG_AIRONET4500_NONCS is not set
++# CONFIG_AIRONET4500_PROC is not set
++# CONFIG_HERMES is not set
++# CONFIG_PCMCIA_HERMES is not set
++CONFIG_AIRO_CS=m
++CONFIG_NET_WIRELESS=y
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# PCMCIA network device support
++#
++CONFIG_NET_PCMCIA=y
++# CONFIG_PCMCIA_3C589 is not set
++CONFIG_PCMCIA_3C574=m
++# CONFIG_PCMCIA_FMVJ18X is not set
++# CONFIG_PCMCIA_PCNET is not set
++# CONFIG_PCMCIA_AXNET is not set
++# CONFIG_PCMCIA_NMCLAN is not set
++# CONFIG_PCMCIA_SMC91C92 is not set
++# CONFIG_PCMCIA_XIRC2PS is not set
++# CONFIG_ARCNET_COM20020_CS is not set
++# CONFIG_PCMCIA_IBMTR is not set
++CONFIG_NET_PCMCIA_RADIO=y
++# CONFIG_PCMCIA_RAYCS is not set
++# CONFIG_PCMCIA_NETWAVE is not set
++# CONFIG_PCMCIA_WAVELAN is not set
++# CONFIG_AIRONET4500_CS is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++CONFIG_IDE=m
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=m
++# CONFIG_BLK_DEV_HD_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++CONFIG_BLK_DEV_IDEDISK=m
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_IDEDISK_STROKE is not set
++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
++# CONFIG_BLK_DEV_IDEDISK_IBM is not set
++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
++# CONFIG_BLK_DEV_IDEDISK_WD is not set
++# CONFIG_BLK_DEV_COMMERIAL is not set
++# CONFIG_BLK_DEV_TIVO is not set
++CONFIG_BLK_DEV_IDECS=m
++# CONFIG_BLK_DEV_IDECD is not set
++# CONFIG_BLK_DEV_IDETAPE is not set
++# CONFIG_BLK_DEV_IDEFLOPPY is not set
++# CONFIG_BLK_DEV_IDESCSI is not set
++# CONFIG_IDE_TASK_IOCTL is not set
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_IDE_MODES is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++# CONFIG_INPUT is not set
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++# CONFIG_VT_CONSOLE is not set
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++CONFIG_I2C_PXA_ALGO=y
++CONFIG_I2C_PXA_ADAP=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_PROC=y
++# CONFIG_I2C_DS1307 is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_QIC02_TAPE is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++CONFIG_PXA_RTC=y
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# PCMCIA character devices
++#
++# CONFIG_PCMCIA_SERIAL_CS is not set
++CONFIG_TRIZEPS2_TTLIO=m
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++CONFIG_EXT3_FS=y
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++# CONFIG_UMSDOS_FS is not set
++CONFIG_VFAT_FS=m
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_CRAMFS is not set
++CONFIG_TMPFS=y
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++# CONFIG_DEVFS_FS is not set
++# CONFIG_DEVFS_MOUNT is not set
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=m
++# CONFIG_NFS_V3 is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++CONFIG_SUNRPC=m
++CONFIG_LOCKD=m
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++# CONFIG_ZLIB_FS_INFLATE is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++# CONFIG_NLS_CODEPAGE_437 is not set
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Console drivers
++#
++CONFIG_PC_KEYMAP=y
++# CONFIG_VGA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++CONFIG_FB=y
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FB_ACORN is not set
++# CONFIG_FB_ANAKIN is not set
++# CONFIG_FB_CLPS711X is not set
++# CONFIG_FB_SA1100 is not set
++CONFIG_FB_PXA=y
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_VIRTUAL is not set
++CONFIG_FBCON_ADVANCED=y
++# CONFIG_FBCON_MFB is not set
++# CONFIG_FBCON_CFB2 is not set
++# CONFIG_FBCON_CFB4 is not set
++# CONFIG_FBCON_CFB8 is not set
++CONFIG_FBCON_CFB16=y
++# CONFIG_FBCON_CFB24 is not set
++# CONFIG_FBCON_CFB32 is not set
++# CONFIG_FBCON_AFB is not set
++# CONFIG_FBCON_ILBM is not set
++# CONFIG_FBCON_IPLAN2P2 is not set
++# CONFIG_FBCON_IPLAN2P4 is not set
++# CONFIG_FBCON_IPLAN2P8 is not set
++# CONFIG_FBCON_MAC is not set
++# CONFIG_FBCON_VGA_PLANES is not set
++# CONFIG_FBCON_VGA is not set
++# CONFIG_FBCON_HGA is not set
++CONFIG_FBCON_FONTWIDTH8_ONLY=y
++CONFIG_FBCON_FONTS=y
++# CONFIG_FONT_8x8 is not set
++# CONFIG_FONT_8x16 is not set
++# CONFIG_FONT_SUN8x16 is not set
++# CONFIG_FONT_PEARL_8x8 is not set
++CONFIG_FONT_ACORN_8x8=y
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_CMPCI is not set
++# CONFIG_SOUND_EMU10K1 is not set
++# CONFIG_MIDI_EMU10K1 is not set
++# CONFIG_SOUND_FUSION is not set
++# CONFIG_SOUND_CS4281 is not set
++# CONFIG_SOUND_ES1370 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ESSSOLO1 is not set
++# CONFIG_SOUND_MAESTRO is not set
++# CONFIG_SOUND_MAESTRO3 is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_RME96XX is not set
++# CONFIG_SOUND_SONICVIBES is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_MIDI_VIA82CXXX is not set
++# CONFIG_SOUND_OSS is not set
++# CONFIG_SOUND_WAVEARTIST is not set
++CONFIG_SOUND_PXA_AC97=y
++# CONFIG_SOUND_TVMIXER is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++CONFIG_MCP=y
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++CONFIG_MCP_UCB1400_TS=y
++CONFIG_MCP_UCB1X00_TS_COMPAT=y
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SLAB is not set
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_WAITQ is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
+--- linux-2.4.27/arch/arm/kernel/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/kernel/Makefile
+@@ -10,7 +10,7 @@
+ HEAD_OBJ = head-$(PROCESSOR).o
+ ENTRY_OBJ = entry-$(PROCESSOR).o
+
+-AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR)
++AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR)
+ AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR)
+
+ # This is depreciated.
+@@ -45,7 +45,7 @@
+ $(CONFIG_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \
+ $(CONFIG_ARCH_SA1100) $(CONFIG_ARCH_CAMELOT) \
+ $(CONFIG_ARCH_MX1ADS) $(CONFIG_ARCH_OMAHA) \
+- $(CONFIG_ARCH_AT91RM9200)
++ $(CONFIG_ARCH_AT91RM9200) $(CONFIG_ARCH_PXA)
+
+ ifneq ($(findstring y,$(no-irq-arch)),y)
+ obj-y += irq-arch.o
+--- linux-2.4.27/arch/arm/kernel/debug-armv.S~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/kernel/debug-armv.S
+@@ -221,6 +221,31 @@
+ bne 1001b
+ .endm
+
++#elif defined(CONFIG_ARCH_PXA)
++
++ .macro addruart,rx
++ mrc p15, 0, \rx, c1, c0
++ tst \rx, #1 @ MMU enabled?
++ moveq \rx, #0x40000000 @ physical
++ movne \rx, #io_p2v(0x40000000) @ virtual
++ orr \rx, \rx, #0x00100000 @ FFUART
++ .endm
++
++ .macro senduart,rd,rx
++ str \rd, [\rx, #0]
++ .endm
++
++ .macro busyuart,rd,rx
++1002: ldr \rd, [\rx, #0x14]
++ tst \rd, #(1 << 6)
++ beq 1002b
++ .endm
++
++ .macro waituart,rd,rx
++1001: ldr \rd, [\rx, #0x14]
++ tst \rd, #(1 << 5)
++ beq 1001b
++ .endm
+ #elif defined(CONFIG_ARCH_CLPS7500)
+ .macro addruart,rx
+ mov \rx, #0xe0000000
+--- linux-2.4.27/arch/arm/kernel/entry-armv.S~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/kernel/entry-armv.S
+@@ -615,6 +615,27 @@
+ .text
+ .endm
+
++#elif CONFIG_ARCH_PXA
++
++ .macro disable_fiq
++ .endm
++
++ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
++ mov \base, #io_p2v(0x40000000) @ IIR Ctl = 0x40d00000
++ add \base, \base, #0x00d00000
++ ldr \irqstat, [\base, #0] @ ICIP
++ ldr \irqnr, [\base, #4] @ ICMR
++ ands \irqstat, \irqstat, \irqnr
++ beq 1001f
++ rsb \irqnr, \irqstat, #0
++ and \irqstat, \irqstat, \irqnr
++ clz \irqnr, \irqstat
++ rsb \irqnr, \irqnr, #(31 - PXA_IRQ_SKIP)
++1001:
++ .endm
++
++ .macro irq_prio_table
++ .endm
+ #else
+ #error Unknown architecture
+ #endif
+@@ -891,9 +912,17 @@
+ stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack
+ mrs ip, cpsr
+ str ip, [sp, #-4]! @ Save cpsr_SVC
++#ifdef CONFIG_CPU_XSCALE
++ mra r4, r5, acc0
++ stmfd sp!, {r4, r5}
++#endif
+ str sp, [r0, #TSS_SAVE] @ Save sp_SVC
+ ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC
+ ldr r2, [r1, #TSS_DOMAIN]
++#ifdef CONFIG_CPU_XSCALE
++ ldmfd sp!, {r4, r5}
++ mar acc0, r4, r5
++#endif
+ ldr ip, [sp], #4
+ mcr p15, 0, r2, c3, c0 @ Set domain register
+ msr spsr, ip @ Save tasks CPSR into SPSR for this return
+--- linux-2.4.27/arch/arm/kernel/head-armv.S~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/kernel/head-armv.S
+@@ -30,6 +30,7 @@
+ *
+ * swapper_pg_dir, pgtbl and krnladr are all closely related.
+ */
++#ifndef CONFIG_XIP_KERNEL
+ #if (TEXTADDR & 0xffff) != 0x8000
+ #error TEXTADDR must start at 0xXXXX8000
+ #endif
+@@ -41,6 +42,26 @@
+ adr \reg, stext
+ sub \reg, \reg, #0x4000
+ .endm
++#else
++#if (DATAADDR & 0xffff) != 0x8000
++#error DATAADDR must start at 0xXXXX8000
++#endif
++
++#define PAGE_OFFSET 0xc0000000
++#ifdef CONFIG_ARCH_LUBBOCK
++#define PHYS_OFFSET 0xa0000000
++#elif CONFIG_ARCH_OMAP
++#define PHYS_OFFSET 0x10000000
++#endif
++
++ .globl SYMBOL_NAME(swapper_pg_dir)
++ .equ SYMBOL_NAME(swapper_pg_dir), DATAADDR - 0x4000
++
++ .macro pgtbl, reg, rambase
++ ldr \reg, PGTBL
++ add \reg, \reg, #PHYS_OFFSET - PAGE_OFFSET
++ .endm
++#endif
+
+ /*
+ * Since the page table is closely related to the kernel start address, we
+@@ -131,6 +152,32 @@
+ mov r1, #MACH_TYPE_L7200
+ #endif
+
++#ifdef CONFIG_XIP_KERNEL
++
++#if defined(CONFIG_ARCH_LUBBOCK)
++ mov r1, #MACH_TYPE_LUBBOCK
++#endif
++
++ @ Data cache might be active.
++ @ Be sure to flush kernel binary out of the cache,
++ @ whatever state it is, before it is turned off.
++ @ This is done by fetching through currently executed
++ @ memory to be sure we hit the same cache.
++ bic r2, pc, #0x1f
++ add r3, r2, #0x10000 @ 64 kb is quite enough...
++1: ldr r0, [r2], #32
++ teq r2, r3
++ bne 1b
++ mcr p15, 0, r0, c7, c10, 4 @ drain WB
++ mcr p15, 0, r0, c7, c7, 0 @ flush I & D caches
++
++ @ disabling MMU and caches
++ mrc p15, 0, r0, c1, c0, 0 @ read control reg
++ bic r0, r0, #0x05 @ clear DC, MMU
++ bic r0, r0, #0x1000 @ clear Icache
++ mcr p15, 0, r0, c1, c0, 0
++#endif
++
+ mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode
+ msr cpsr_c, r0 @ and all irqs disabled
+ bl __lookup_processor_type
+@@ -179,6 +226,17 @@
+ */
+ .align 5
+ __mmap_switched:
++#ifdef CONFIG_XIP_KERNEL
++ ldr r3, ETEXT @ data section copy
++ ldr r4, SDATA
++ ldr r5, EDATA
++1:
++ ldr r6, [r3], #4
++ str r6, [r4], #4
++ cmp r4, r5
++ blo 1b
++#endif
++
+ adr r3, __switch_data + 4
+ ldmia r3, {r4, r5, r6, r7, r8, sp}@ r2 = compat
+ @ sp = stack pointer
+@@ -233,6 +291,8 @@
+ teq r0, r2
+ bne 1b
+
++#ifndef CONFIG_XIP_KERNEL
++
+ /*
+ * Create identity mapping for first MB of kernel to
+ * cater for the MMU enable. This identity mapping
+@@ -271,6 +331,43 @@
+ add r3, r8, r2 @ flags + rambase
+ str r3, [r0]
+
++#else /* CONFIG_XIP_KERNEL */
++
++ mov r3, pc, lsr #20
++ mov r3, r3, lsl #20 @ phys kernel start
++
++ add r0, r4, r3, lsr #18
++ orr r3, r3, r8
++ str r3, [r0]
++
++ mov r0, #TEXTADDR & 0xff000000
++ add r0, r0, #TEXTADDR & 0x00f00000 @ virt kernel start
++ add r0, r4, r0, lsr #18
++ add r2, r3, #4 << 20 @ kernel + 4MB
++
++1:
++ str r3, [r0], #4
++ add r3, r3, #1 << 20
++ cmp r3, r2
++ bne 1b
++
++ bic r3, r4, #0x000ff000 @ ram start
++ add r0, r4, r3, lsr #18
++ orr r3, r3, r8
++ str r3, [r0], #4
++
++ add r0, r3, #PAGE_OFFSET - PHYS_OFFSET
++ add r0, r4, r0, lsr #18
++ add r2, r3, #4 << 20 @ ram + 4MB
++
++1:
++ str r3, [r0], #4
++ add r3, r3, #1 << 20
++ cmp r3, r2
++ bne 1b
++
++#endif /* CONFIG_XIP_KERNEL */
++
+ bic r8, r8, #0x0c @ turn off cacheable
+ @ and bufferable bits
+ #ifdef CONFIG_DEBUG_LL
+@@ -433,3 +530,13 @@
+ mov pc, lr
+ 2: ldmib r4, {r5, r6, r7} @ found, get results
+ mov pc, lr
++
++#ifdef CONFIG_XIP_KERNEL
++
++PGTBL: .long SYMBOL_NAME(swapper_pg_dir)
++
++ETEXT: .long SYMBOL_NAME(_endtext)
++SDATA: .long SYMBOL_NAME(_sdata)
++EDATA: .long SYMBOL_NAME(__bss_start)
++
++#endif
+--- linux-2.4.27/arch/arm/kernel/setup.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/kernel/setup.c
+@@ -55,6 +55,10 @@
+ extern void reboot_setup(char *str);
+ extern int root_mountflags;
+ extern int _stext, _text, _etext, _edata, _end;
++#ifdef CONFIG_XIP_KERNEL
++extern int _endtext, _sdata;
++#endif
++
+
+ unsigned int processor_id;
+ unsigned int __machine_arch_type;
+@@ -105,6 +109,109 @@
+ #define lp1 io_res[1]
+ #define lp2 io_res[2]
+
++#ifdef CONFIG_CPU_32
++static const char *cache_types[16] = {
++ "write-through",
++ "write-back",
++ "write-back",
++ "undefined 3",
++ "undefined 4",
++ "undefined 5",
++ "write-back",
++ "write-back",
++ "undefined 8",
++ "undefined 9",
++ "undefined 10",
++ "undefined 11",
++ "undefined 12",
++ "undefined 13",
++ "undefined 14",
++ "undefined 15",
++};
++
++static const char *cache_clean[16] = {
++ "not required",
++ "read-block",
++ "cp15 c7 ops",
++ "undefined 3",
++ "undefined 4",
++ "undefined 5",
++ "cp15 c7 ops",
++ "cp15 c7 ops",
++ "undefined 8",
++ "undefined 9",
++ "undefined 10",
++ "undefined 11",
++ "undefined 12",
++ "undefined 13",
++ "undefined 14",
++ "undefined 15",
++};
++
++static const char *cache_lockdown[16] = {
++ "not supported",
++ "not supported",
++ "not supported",
++ "undefined 3",
++ "undefined 4",
++ "undefined 5",
++ "format A",
++ "format B",
++ "undefined 8",
++ "undefined 9",
++ "undefined 10",
++ "undefined 11",
++ "undefined 12",
++ "undefined 13",
++ "undefined 14",
++ "undefined 15",
++};
++
++#define CACHE_TYPE(x) (((x) >> 25) & 15)
++#define CACHE_S(x) ((x) & (1 << 24))
++#define CACHE_DSIZE(x) (((x) >> 12) & 4095) /* only if S=1 */
++#define CACHE_ISIZE(x) ((x) & 4095)
++
++#define CACHE_SIZE(y) (((y) >> 6) & 7)
++#define CACHE_ASSOC(y) (((y) >> 3) & 7)
++#define CACHE_M(y) ((y) & (1 << 2))
++#define CACHE_LINE(y) ((y) & 3)
++
++static inline void dump_cache(const char *prefix, unsigned int cache)
++{
++ unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
++
++ printk("%s size %dK associativity %d line length %d sets %d\n",
++ prefix,
++ mult << (8 + CACHE_SIZE(cache)),
++ (mult << CACHE_ASSOC(cache)) >> 1,
++ 8 << CACHE_LINE(cache),
++ 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
++ CACHE_LINE(cache)));
++}
++
++static inline void dump_cpu_cache_id(void)
++{
++ unsigned int cache_info;
++
++ asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info));
++
++ if (cache_info == processor_id)
++ return;
++
++ printk("CPU: D %s cache\n", cache_types[CACHE_TYPE(cache_info)]);
++ if (CACHE_S(cache_info)) {
++ dump_cache("CPU: I cache", CACHE_ISIZE(cache_info));
++ dump_cache("CPU: D cache", CACHE_DSIZE(cache_info));
++ } else {
++ dump_cache("CPU: cache", CACHE_ISIZE(cache_info));
++ }
++}
++
++#else
++#define dump_cpu_cache_id() do { } while (0)
++#endif
++
+ static void __init setup_processor(void)
+ {
+ extern struct proc_info_list __proc_info_begin, __proc_info_end;
+@@ -272,7 +379,11 @@
+
+ kernel_code.start = __virt_to_phys(init_mm.start_code);
+ kernel_code.end = __virt_to_phys(init_mm.end_code - 1);
++#ifndef CONFIG_XIP_KERNEL
+ kernel_data.start = __virt_to_phys(init_mm.end_code);
++#else
++ kernel_data.start = __virt_to_phys(init_mm.start_data);
++#endif
+ kernel_data.end = __virt_to_phys(init_mm.brk - 1);
+
+ for (i = 0; i < mi->nr_banks; i++) {
+@@ -531,7 +642,12 @@
+ }
+
+ init_mm.start_code = (unsigned long) &_text;
++#ifndef CONFIG_XIP_KERNEL
+ init_mm.end_code = (unsigned long) &_etext;
++#else
++ init_mm.end_code = (unsigned long) &_endtext;
++ init_mm.start_data = (unsigned long) &_sdata;
++#endif
+ init_mm.end_data = (unsigned long) &_edata;
+ init_mm.brk = (unsigned long) &_end;
+
+@@ -568,6 +684,41 @@
+ NULL
+ };
+
++static const char *proc_arch[16] = {
++ "undefined 0",
++ "4",
++ "4T",
++ "5",
++ "5T",
++ "5TE",
++ "undefined 6",
++ "undefined 7",
++ "undefined 8",
++ "undefined 9",
++ "undefined 10",
++ "undefined 11",
++ "undefined 12",
++ "undefined 13",
++ "undefined 14",
++ "undefined 15"
++};
++
++static void
++c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
++{
++ unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
++
++ seq_printf(m, "%s size\t\t: %d\n"
++ "%s assoc\t\t: %d\n"
++ "%s line length\t: %d\n"
++ "%s sets\t\t: %d\n",
++ type, mult << (8 + CACHE_SIZE(cache)),
++ type, (mult << CACHE_ASSOC(cache)) >> 1,
++ type, 8 << CACHE_LINE(cache),
++ type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
++ CACHE_LINE(cache)));
++}
++
+ static int c_show(struct seq_file *m, void *v)
+ {
+ int i;
+@@ -586,7 +737,60 @@
+ if (elf_hwcap & (1 << i))
+ seq_printf(m, "%s ", hwcap_str[i]);
+
+- seq_puts(m, "\n\n");
++ seq_puts(m, "\n");
++
++ if ((processor_id & 0x0000f000) == 0x00000000) {
++ /* pre-ARM7 */
++ seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4);
++ } else if ((processor_id & 0x0000f000) == 0x00007000) {
++ /* ARM7 */
++ seq_printf(m, "CPU implementor\t: 0x%02x\n"
++ "CPU architecture: %s\n"
++ "CPU variant\t: 0x%02x\n"
++ "CPU part\t: 0x%03x\n",
++ processor_id >> 24,
++ processor_id & (1 << 23) ? "4T" : "3",
++ (processor_id >> 16) & 127,
++ (processor_id >> 4) & 0xfff);
++ } else {
++ /* post-ARM7 */
++ seq_printf(m, "CPU implementor\t: 0x%02x\n"
++ "CPU architecture: %s\n"
++ "CPU variant\t: 0x%x\n"
++ "CPU part\t: 0x%03x\n",
++ processor_id >> 24,
++ proc_arch[(processor_id >> 16) & 15],
++ (processor_id >> 20) & 15,
++ (processor_id >> 4) & 0xfff);
++ }
++ seq_printf(m, "CPU revision\t: %d\n", processor_id & 15);
++
++#ifdef CONFIG_CPU_32
++ {
++ unsigned int cache_info;
++
++ asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info));
++ if (cache_info != processor_id) {
++ seq_printf(m, "Cache type\t: %s\n"
++ "Cache clean\t: %s\n"
++ "Cache lockdown\t: %s\n"
++ "Cache unified\t: %s\n",
++ cache_types[CACHE_TYPE(cache_info)],
++ cache_clean[CACHE_TYPE(cache_info)],
++ cache_lockdown[CACHE_TYPE(cache_info)],
++ CACHE_S(cache_info) ? "harvard" : "unified");
++
++ if (CACHE_S(cache_info)) {
++ c_show_cache(m, "I", CACHE_ISIZE(cache_info));
++ c_show_cache(m, "D", CACHE_DSIZE(cache_info));
++ } else {
++ c_show_cache(m, "Cache", CACHE_ISIZE(cache_info));
++ }
++ }
++ }
++#endif
++
++ seq_puts(m, "\n");
+
+ seq_printf(m, "Hardware\t: %s\n", machine_name);
+ seq_printf(m, "Revision\t: %04x\n", system_rev);
+--- linux-2.4.27/arch/arm/lib/copy_page.S~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/lib/copy_page.S
+@@ -13,6 +13,8 @@
+ #include <asm/assembler.h>
+ #include <asm/constants.h>
+
++#define COPY_COUNT (PAGE_SZ/64 PLD( -1 ))
++
+ .text
+ .align 5
+ /*
+@@ -23,9 +25,13 @@
+ */
+ ENTRY(copy_page)
+ stmfd sp!, {r4, lr} @ 2
+- mov r2, #PAGE_SZ/64 @ 1
++ PLD( pld [r1, #0] )
++ PLD( pld [r1, #32] )
++ mov r2, #COPY_COUNT @ 1
+ ldmia r1!, {r3, r4, ip, lr} @ 4+1
+-1: stmia r0!, {r3, r4, ip, lr} @ 4
++1: PLD( pld [r1, #64] )
++ PLD( pld [r1, #96] )
++2: stmia r0!, {r3, r4, ip, lr} @ 4
+ ldmia r1!, {r3, r4, ip, lr} @ 4+1
+ stmia r0!, {r3, r4, ip, lr} @ 4
+ ldmia r1!, {r3, r4, ip, lr} @ 4+1
+@@ -33,6 +39,8 @@
+ ldmia r1!, {r3, r4, ip, lr} @ 4
+ subs r2, r2, #1 @ 1
+ stmia r0!, {r3, r4, ip, lr} @ 4
+- ldmneia r1!, {r3, r4, ip, lr} @ 4
+- bne 1b @ 1
++ ldmgtia r1!, {r3, r4, ip, lr} @ 4
++ bgt 1b @ 1
++ PLD( ldmeqia r1!, {r3, r4, ip, lr} )
++ PLD( beq 2b )
+ LOADREGS(fd, sp!, {r4, pc}) @ 3
+--- linux-2.4.27/arch/arm/lib/findbit.S~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/lib/findbit.S
+@@ -43,7 +43,15 @@
+ /*
+ * One or more bits in the LSB of r3 are assumed to be set.
+ */
+-.found: tst r3, #0x0f
++.found:
++#if __LINUX_ARM_ARCH__ >= 5
++ rsb r1, r3, #0
++ and r3, r3, r1
++ clz r3, r3
++ rsb r3, r3, #31
++ add r0, r2, r3
++#else
++ tst r3, #0x0f
+ addeq r2, r2, #4
+ movne r3, r3, lsl #4
+ tst r3, #0x30
+@@ -52,5 +60,6 @@
+ tst r3, #0x40
+ addeq r2, r2, #1
+ mov r0, r2
++#endif
+ RETINSTR(mov,pc,lr)
+
+--- linux-2.4.27/arch/arm/lib/getuser.S~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/lib/getuser.S
+@@ -18,7 +18,7 @@
+ * Inputs: r0 contains the address
+ * Outputs: r0 is the error code
+ * r1, r2 contains the zero-extended value
+- * lr corrupted
++ * ip, lr corrupted
+ *
+ * No other registers must be altered. (see include/asm-arm/uaccess.h
+ * for specific ASM register usage).
+@@ -42,14 +42,14 @@
+
+ .global __get_user_2
+ __get_user_2:
+- bic r2, sp, #0x1f00
+- bic r2, r2, #0x00ff
+- ldr r2, [r2, #TSK_ADDR_LIMIT]
+- sub r2, r2, #2
+- cmp r0, r2
++ bic ip, sp, #0x1f00
++ bic ip, ip, #0x00ff
++ ldr ip, [ip, #TSK_ADDR_LIMIT]
++ sub ip, ip, #2
++ cmp r0, ip
+ 2: ldrlsbt r1, [r0], #1
+-3: ldrlsbt r2, [r0]
+- orrls r1, r1, r2, lsl #8
++3: ldrlsbt ip, [r0]
++ orrls r1, r1, ip, lsl #8
+ movls r0, #0
+ movls pc, lr
+ b __get_user_bad
+--- linux-2.4.27/arch/arm/lib/memcpy.S~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/lib/memcpy.S
+@@ -8,6 +8,9 @@
+ * published by the Free Software Foundation.
+ *
+ * ASM optimised string functions
++ *
++ * Big Endian, prefetching and code factorization provided by Nicolas Pitre:
++ * Copyright (C) 2002-2003 MontaVista Software, Inc.
+ */
+ #include <linux/linkage.h>
+ #include <asm/assembler.h>
+@@ -27,15 +30,16 @@
+
+ /*
+ * Prototype: void memcpy(void *to,const void *from,unsigned long n);
+- * ARM3: cant use memcopy here!!!
+ */
+ ENTRY(memcpy)
+ ENTRY(memmove)
+ ENTER
+- cmp r1, r0
+- bcc 19f
++ subs ip, r0, r1
++ cmphi r2, ip
++ bhi 18f
+ subs r2, r2, #4
+ blt 6f
++ PLD( pld [r1, #0] )
+ ands ip, r0, #3
+ bne 7f
+ ands ip, r1, #3
+@@ -43,29 +47,59 @@
+
+ 1: subs r2, r2, #8
+ blt 5f
+- subs r2, r2, #0x14
+- blt 3f
+-2: ldmia r1!,{r3 - r9, ip}
+- stmia r0!,{r3 - r9, ip}
++ subs r2, r2, #20
++ blt 4f
++
++ PLD( subs r2, r2, #65 )
++ PLD( blt 3f )
++ PLD( pld [r1, #32] )
++
++ PLD( @ cache alignment )
++ PLD( ands ip, r1, #31 )
++ PLD( pld [r1, #64] )
++ PLD( beq 2f )
++ PLD( rsb ip, ip, #32 )
++ PLD( cmp r2, ip )
++ PLD( pld [r1, #96] )
++ PLD( blt 2f )
++ PLD( cmp ip, #16 )
++ PLD( sub r2, r2, ip )
++ PLD( ldmgeia r1!, {r3 - r6} )
++ PLD( stmgeia r0!, {r3 - r6} )
++ PLD( beq 2f )
++ PLD( and ip, ip, #15 )
++ PLD( cmp ip, #8 )
++ PLD( ldr r3, [r1], #4 )
++ PLD( ldrge r4, [r1], #4 )
++ PLD( ldrgt r5, [r1], #4 )
++ PLD( str r3, [r0], #4 )
++ PLD( strge r4, [r0], #4 )
++ PLD( strgt r5, [r0], #4 )
++
++2: PLD( pld [r1, #96] )
++3: ldmia r1!, {r3 - r9, ip}
+ subs r2, r2, #32
++ stmia r0!, {r3 - r9, ip}
+ bge 2b
+- cmn r2, #16
++ PLD( cmn r2, #65 )
++ PLD( bge 3b )
++ PLD( add r2, r2, #65 )
++4: cmn r2, #16
+ ldmgeia r1!, {r3 - r6}
++ subge r2, r2, #16
+ stmgeia r0!, {r3 - r6}
+- subge r2, r2, #0x10
+-3: adds r2, r2, #0x14
+-4: ldmgeia r1!, {r3 - r5}
++ adds r2, r2, #20
++ ldmgeia r1!, {r3 - r5}
++ subge r2, r2, #12
+ stmgeia r0!, {r3 - r5}
+- subges r2, r2, #12
+- bge 4b
+ 5: adds r2, r2, #8
+ blt 6f
+ subs r2, r2, #4
+ ldrlt r3, [r1], #4
+ ldmgeia r1!, {r4, r5}
++ subge r2, r2, #4
+ strlt r3, [r0], #4
+ stmgeia r0!, {r4, r5}
+- subge r2, r2, #4
+
+ 6: adds r2, r2, #4
+ EXITEQ
+@@ -92,122 +126,175 @@
+ beq 1b
+
+ 8: bic r1, r1, #3
+- ldr r7, [r1], #4
+ cmp ip, #2
+- bgt 15f
+- beq 11f
++ ldr lr, [r1], #4
++ bgt 17f
++ beq 16f
++
++
++ .macro forward_copy_shift pull push
++
+ cmp r2, #12
+- blt 10f
+- sub r2, r2, #12
+-9: mov r3, r7, lsr #8
+- ldmia r1!, {r4 - r7}
+- orr r3, r3, r4, lsl #24
+- mov r4, r4, lsr #8
+- orr r4, r4, r5, lsl #24
+- mov r5, r5, lsr #8
+- orr r5, r5, r6, lsl #24
+- mov r6, r6, lsr #8
+- orr r6, r6, r7, lsl #24
++ PLD( pld [r1, #0] )
++ blt 14f
++ subs r2, r2, #28
++ blt 12f
++
++ PLD( subs r2, r2, #97 )
++ PLD( blt 11f )
++ PLD( pld [r1, #32] )
++
++ PLD( @ cache alignment )
++ PLD( rsb ip, r1, #36 )
++ PLD( pld [r1, #64] )
++ PLD( ands ip, ip, #31 )
++ PLD( pld [r1, #96] )
++ PLD( beq 10f )
++ PLD( cmp r2, ip )
++ PLD( pld [r1, #128] )
++ PLD( blt 10f )
++ PLD( sub r2, r2, ip )
++9: PLD( mov r3, lr, pull #\pull )
++ PLD( ldr lr, [r1], #4 )
++ PLD( subs ip, ip, #4 )
++ PLD( orr r3, r3, lr, push #\push )
++ PLD( str r3, [r0], #4 )
++ PLD( bgt 9b )
++
++10: PLD( pld [r1, #128] )
++11: mov r3, lr, pull #\pull
++ ldmia r1!, {r4 - r9, ip, lr}
++ subs r2, r2, #32
++ orr r3, r3, r4, push #\push
++ mov r4, r4, pull #\pull
++ orr r4, r4, r5, push #\push
++ mov r5, r5, pull #\pull
++ orr r5, r5, r6, push #\push
++ mov r6, r6, pull #\pull
++ orr r6, r6, r7, push #\push
++ mov r7, r7, pull #\pull
++ orr r7, r7, r8, push #\push
++ mov r8, r8, pull #\pull
++ orr r8, r8, r9, push #\push
++ mov r9, r9, pull #\pull
++ orr r9, r9, ip, push #\push
++ mov ip, ip, pull #\pull
++ orr ip, ip, lr, push #\push
++ stmia r0!, {r3 - r9, ip}
++ bge 10b
++ PLD( cmn r2, #97 )
++ PLD( bge 11b )
++ PLD( add r2, r2, #97 )
++ cmn r2, #16
++ blt 13f
++12: mov r3, lr, pull #\pull
++ ldmia r1!, {r4 - r6, lr}
++ sub r2, r2, #16
++ orr r3, r3, r4, push #\push
++ mov r4, r4, pull #\pull
++ orr r4, r4, r5, push #\push
++ mov r5, r5, pull #\pull
++ orr r5, r5, r6, push #\push
++ mov r6, r6, pull #\pull
++ orr r6, r6, lr, push #\push
+ stmia r0!, {r3 - r6}
+- subs r2, r2, #16
+- bge 9b
+- adds r2, r2, #12
+- blt 100f
+-10: mov r3, r7, lsr #8
+- ldr r7, [r1], #4
++13: adds r2, r2, #28
++ blt 15f
++14: mov r3, lr, pull #\pull
++ ldr lr, [r1], #4
+ subs r2, r2, #4
+- orr r3, r3, r7, lsl #24
++ orr r3, r3, lr, push #\push
+ str r3, [r0], #4
+- bge 10b
+-100: sub r1, r1, #3
++ bge 14b
++15:
++ .endm
++
++
++ forward_copy_shift pull=8 push=24
++ sub r1, r1, #3
+ b 6b
+
+-11: cmp r2, #12
+- blt 13f /* */
+- sub r2, r2, #12
+-12: mov r3, r7, lsr #16
+- ldmia r1!, {r4 - r7}
+- orr r3, r3, r4, lsl #16
+- mov r4, r4, lsr #16
+- orr r4, r4, r5, lsl #16
+- mov r5, r5, lsr #16
+- orr r5, r5, r6, lsl #16
+- mov r6, r6, lsr #16
+- orr r6, r6, r7,LSL#16
+- stmia r0!, {r3 - r6}
+- subs r2, r2, #16
+- bge 12b
+- adds r2, r2, #12
+- blt 14f
+-13: mov r3, r7, lsr #16
+- ldr r7, [r1], #4
+- subs r2, r2, #4
+- orr r3, r3, r7, lsl #16
+- str r3, [r0], #4
+- bge 13b
+-14: sub r1, r1, #2
++16: forward_copy_shift pull=16 push=16
++ sub r1, r1, #2
+ b 6b
+
+-15: cmp r2, #12
+- blt 17f
+- sub r2, r2, #12
+-16: mov r3, r7, lsr #24
+- ldmia r1!,{r4 - r7}
+- orr r3, r3, r4, lsl #8
+- mov r4, r4, lsr #24
+- orr r4, r4, r5, lsl #8
+- mov r5, r5, lsr #24
+- orr r5, r5, r6, lsl #8
+- mov r6, r6, lsr #24
+- orr r6, r6, r7, lsl #8
+- stmia r0!, {r3 - r6}
+- subs r2, r2, #16
+- bge 16b
+- adds r2, r2, #12
+- blt 18f
+-17: mov r3, r7, lsr #24
+- ldr r7, [r1], #4
+- subs r2, r2, #4
+- orr r3, r3, r7, lsl#8
+- str r3, [r0], #4
+- bge 17b
+-18: sub r1, r1, #1
++17: forward_copy_shift pull=24 push=8
++ sub r1, r1, #1
+ b 6b
+
+
+-19: add r1, r1, r2
++18: add r1, r1, r2
+ add r0, r0, r2
+ subs r2, r2, #4
+ blt 24f
++ PLD( pld [r1, #-4] )
+ ands ip, r0, #3
+ bne 25f
+ ands ip, r1, #3
+ bne 26f
+
+-20: subs r2, r2, #8
++19: subs r2, r2, #8
+ blt 23f
+- subs r2, r2, #0x14
++ subs r2, r2, #20
+ blt 22f
+-21: ldmdb r1!, {r3 - r9, ip}
+- stmdb r0!, {r3 - r9, ip}
++
++ PLD( subs r2, r2, #96 )
++ PLD( pld [r1, #-32] )
++ PLD( blt 21f )
++
++ PLD( @ cache alignment )
++ PLD( ands ip, r1, #31 )
++ PLD( pld [r1, #-64] )
++ PLD( beq 20f )
++ PLD( cmp r2, ip )
++ PLD( pld [r1, #-96] )
++ PLD( blt 20f )
++ PLD( cmp ip, #16 )
++ PLD( sub r2, r2, ip )
++ PLD( ldmgedb r1!, {r3 - r6} )
++ PLD( stmgedb r0!, {r3 - r6} )
++ PLD( beq 20f )
++ PLD( and ip, ip, #15 )
++ PLD( cmp ip, #8 )
++ PLD( ldr r3, [r1, #-4]! )
++ PLD( ldrge r4, [r1, #-4]! )
++ PLD( ldrgt r5, [r1, #-4]! )
++ PLD( str r3, [r0, #-4]! )
++ PLD( strge r4, [r0, #-4]! )
++ PLD( strgt r5, [r0, #-4]! )
++
++20: PLD( pld [r1, #-96] )
++ PLD( pld [r1, #-128] )
++21: ldmdb r1!, {r3 - r6}
+ subs r2, r2, #32
+- bge 21b
+-22: cmn r2, #16
++ stmdb r0!, {r3 - r6}
++ ldmdb r1!, {r3 - r6}
++ stmgedb r0!, {r3 - r6}
+ ldmgedb r1!, {r3 - r6}
+ stmgedb r0!, {r3 - r6}
++ ldmgedb r1!, {r3 - r6}
++ subges r2, r2, #32
++ stmdb r0!, {r3 - r6}
++ bge 20b
++ PLD( cmn r2, #96 )
++ PLD( bge 21b )
++ PLD( add r2, r2, #96 )
++22: cmn r2, #16
++ ldmgedb r1!, {r3 - r6}
+ subge r2, r2, #16
++ stmgedb r0!, {r3 - r6}
+ adds r2, r2, #20
+ ldmgedb r1!, {r3 - r5}
+- stmgedb r0!, {r3 - r5}
+ subge r2, r2, #12
++ stmgedb r0!, {r3 - r5}
+ 23: adds r2, r2, #8
+ blt 24f
+ subs r2, r2, #4
+ ldrlt r3, [r1, #-4]!
+ ldmgedb r1!, {r4, r5}
++ subge r2, r2, #4
+ strlt r3, [r0, #-4]!
+ stmgedb r0!, {r4, r5}
+- subge r2, r2, #4
+
+ 24: adds r2, r2, #4
+ EXITEQ
+@@ -230,89 +317,101 @@
+ subs r2, r2, ip
+ blt 24b
+ ands ip, r1, #3
+- beq 20b
++ beq 19b
+
+ 26: bic r1, r1, #3
+- ldr r3, [r1], #0
+ cmp ip, #2
+- blt 34f
+- beq 30f
+- cmp r2, #12
+- blt 28f
+- sub r2, r2, #12
+-27: mov r7, r3, lsl #8
+- ldmdb r1!, {r3, r4, r5, r6}
+- orr r7, r7, r6, lsr #24
+- mov r6, r6, lsl #8
+- orr r6, r6, r5, lsr #24
+- mov r5, r5, lsl #8
+- orr r5, r5, r4, lsr #24
+- mov r4, r4, lsl #8
+- orr r4, r4, r3, lsr #24
+- stmdb r0!, {r4, r5, r6, r7}
+- subs r2, r2, #16
+- bge 27b
+- adds r2, r2, #12
+- blt 29f
+-28: mov ip, r3, lsl #8
+- ldr r3, [r1, #-4]!
+- subs r2, r2, #4
+- orr ip, ip, r3, lsr #24
+- str ip, [r0, #-4]!
+- bge 28b
+-29: add r1, r1, #3
+- b 24b
++ ldr r3, [r1], #0
++ blt 35f
++ beq 34f
+
+-30: cmp r2, #12
++
++ .macro backward_copy_shift push pull
++
++ cmp r2, #12
++ PLD( pld [r1, #-4] )
+ blt 32f
+- sub r2, r2, #12
+-31: mov r7, r3, lsl #16
+- ldmdb r1!, {r3, r4, r5, r6}
+- orr r7, r7, r6, lsr #16
+- mov r6, r6, lsl #16
+- orr r6, r6, r5, lsr #16
+- mov r5, r5, lsl #16
+- orr r5, r5, r4, lsr #16
+- mov r4, r4, lsl #16
+- orr r4, r4, r3, lsr #16
+- stmdb r0!, {r4, r5, r6, r7}
+- subs r2, r2, #16
+- bge 31b
+- adds r2, r2, #12
++ subs r2, r2, #28
++ blt 30f
++
++ PLD( subs r2, r2, #96 )
++ PLD( pld [r1, #-32] )
++ PLD( blt 29f )
++ PLD( pld [r1, #-64] )
++
++ PLD( @ cache alignment )
++ PLD( ands ip, r1, #31 )
++ PLD( pld [r1, #-96] )
++ PLD( beq 28f )
++ PLD( cmp r2, ip )
++ PLD( pld [r1, #-128] )
++ PLD( blt 28f )
++ PLD( sub r2, r2, ip )
++27: PLD( mov r4, r3, push #\push )
++ PLD( ldr r3, [r1, #-4]! )
++ PLD( subs ip, ip, #4 )
++ PLD( orr r4, r4, r3, pull #\pull )
++ PLD( str r4, [r0, #-4]! )
++ PLD( bgt 27b )
++
++28: PLD( pld [r1, #-128] )
++29: mov lr, r3, push #\push
++ ldmdb r1!, {r3 - r9, ip}
++ subs r2, r2, #32
++ orr lr, lr, ip, pull #\pull
++ mov ip, ip, push #\push
++ orr ip, ip, r9, pull #\pull
++ mov r9, r9, push #\push
++ orr r9, r9, r8, pull #\pull
++ mov r8, r8, push #\push
++ orr r8, r8, r7, pull #\pull
++ mov r7, r7, push #\push
++ orr r7, r7, r6, pull #\pull
++ mov r6, r6, push #\push
++ orr r6, r6, r5, pull #\pull
++ mov r5, r5, push #\push
++ orr r5, r5, r4, pull #\pull
++ mov r4, r4, push #\push
++ orr r4, r4, r3, pull #\pull
++ stmdb r0!, {r4 - r9, ip, lr}
++ bge 28b
++ PLD( cmn r2, #96 )
++ PLD( bge 29b )
++ PLD( add r2, r2, #96 )
++ cmn r2, #16
++ blt 31f
++30: mov r7, r3, push #\push
++ ldmdb r1!, {r3 - r6}
++ sub r2, r2, #16
++ orr r7, r7, r6, pull #\pull
++ mov r6, r6, push #\push
++ orr r6, r6, r5, pull #\pull
++ mov r5, r5, push #\push
++ orr r5, r5, r4, pull #\pull
++ mov r4, r4, push #\push
++ orr r4, r4, r3, pull #\pull
++ stmdb r0!, {r4 - r7}
++31: adds r2, r2, #28
+ blt 33f
+-32: mov ip, r3, lsl #16
++32: mov r4, r3, push #\push
+ ldr r3, [r1, #-4]!
+ subs r2, r2, #4
+- orr ip, ip, r3, lsr #16
+- str ip, [r0, #-4]!
++ orr r4, r4, r3, pull #\pull
++ str r4, [r0, #-4]!
+ bge 32b
+-33: add r1, r1, #2
++33:
++ .endm
++
++
++ backward_copy_shift push=8 pull=24
++ add r1, r1, #3
+ b 24b
+
+-34: cmp r2, #12
+- blt 36f
+- sub r2, r2, #12
+-35: mov r7, r3, lsl #24
+- ldmdb r1!, {r3, r4, r5, r6}
+- orr r7, r7, r6, lsr #8
+- mov r6, r6, lsl #24
+- orr r6, r6, r5, lsr #8
+- mov r5, r5, lsl #24
+- orr r5, r5, r4, lsr #8
+- mov r4, r4, lsl #24
+- orr r4, r4, r3, lsr #8
+- stmdb r0!, {r4, r5, r6, r7}
+- subs r2, r2, #16
+- bge 35b
+- adds r2, r2, #12
+- blt 37f
+-36: mov ip, r3, lsl #24
+- ldr r3, [r1, #-4]!
+- subs r2, r2, #4
+- orr ip, ip, r3, lsr #8
+- str ip, [r0, #-4]!
+- bge 36b
+-37: add r1, r1, #1
++34: backward_copy_shift push=16 pull=16
++ add r1, r1, #2
++ b 24b
++
++35: backward_copy_shift push=24 pull=8
++ add r1, r1, #1
+ b 24b
+
+- .align
+--- linux-2.4.27/arch/arm/lib/uaccess.S~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/lib/uaccess.S
+@@ -43,6 +43,8 @@
+ stmfd sp!, {r2, r4 - r7, lr}
+ cmp r2, #4
+ blt .c2u_not_enough
++ PLD( pld [r1, #0] )
++ PLD( pld [r0, #0] )
+ ands ip, r0, #3
+ bne .c2u_dest_not_aligned
+ .c2u_dest_aligned:
+@@ -71,13 +73,26 @@
+ sub r2, r2, ip
+ subs ip, ip, #32
+ blt .c2u_0rem8lp
++ PLD( pld [r1, #28] )
++ PLD( pld [r0, #28] )
++ PLD( subs ip, ip, #64 )
++ PLD( blt .c2u_0cpynopld )
++ PLD( pld [r1, #60] )
++ PLD( pld [r0, #60] )
+
+-.c2u_0cpy8lp: ldmia r1!, {r3 - r6}
++.c2u_0cpy8lp:
++ PLD( pld [r1, #92] )
++ PLD( pld [r0, #92] )
++.c2u_0cpynopld: ldmia r1!, {r3 - r6}
+ stmia r0!, {r3 - r6} @ Shouldnt fault
+ ldmia r1!, {r3 - r6}
+- stmia r0!, {r3 - r6} @ Shouldnt fault
+ subs ip, ip, #32
++ stmia r0!, {r3 - r6} @ Shouldnt fault
+ bpl .c2u_0cpy8lp
++ PLD( cmn ip, #64 )
++ PLD( bge .c2u_0cpynopld )
++ PLD( add ip, ip, #64 )
++
+ .c2u_0rem8lp: cmn ip, #16
+ ldmgeia r1!, {r3 - r6}
+ stmgeia r0!, {r3 - r6} @ Shouldnt fault
+@@ -115,9 +130,9 @@
+ .c2u_1fupi: subs r2, r2, #4
+ addmi ip, r2, #4
+ bmi .c2u_1nowords
+- mov r3, r7, lsr #8
++ mov r3, r7, pull #8
+ ldr r7, [r1], #4
+- orr r3, r3, r7, lsl #24
++ orr r3, r3, r7, push #24
+ USER( strt r3, [r0], #4) @ May fault
+ mov ip, r0, lsl #32 - PAGE_SHIFT
+ rsb ip, ip, #0
+@@ -128,50 +143,63 @@
+ sub r2, r2, ip
+ subs ip, ip, #16
+ blt .c2u_1rem8lp
++ PLD( pld [r1, #12] )
++ PLD( pld [r0, #12] )
++ PLD( subs ip, ip, #32 )
++ PLD( blt .c2u_1cpynopld )
++ PLD( pld [r1, #28] )
++ PLD( pld [r0, #28] )
+
+-.c2u_1cpy8lp: mov r3, r7, lsr #8
++.c2u_1cpy8lp:
++ PLD( pld [r1, #44] )
++ PLD( pld [r0, #44] )
++.c2u_1cpynopld: mov r3, r7, pull #8
+ ldmia r1!, {r4 - r7}
+- orr r3, r3, r4, lsl #24
+- mov r4, r4, lsr #8
+- orr r4, r4, r5, lsl #24
+- mov r5, r5, lsr #8
+- orr r5, r5, r6, lsl #24
+- mov r6, r6, lsr #8
+- orr r6, r6, r7, lsl #24
+- stmia r0!, {r3 - r6} @ Shouldnt fault
+ subs ip, ip, #16
++ orr r3, r3, r4, push #24
++ mov r4, r4, pull #8
++ orr r4, r4, r5, push #24
++ mov r5, r5, pull #8
++ orr r5, r5, r6, push #24
++ mov r6, r6, pull #8
++ orr r6, r6, r7, push #24
++ stmia r0!, {r3 - r6} @ Shouldnt fault
+ bpl .c2u_1cpy8lp
++ PLD( cmn ip, #32 )
++ PLD( bge .c2u_1cpynopld )
++ PLD( add ip, ip, #32 )
++
+ .c2u_1rem8lp: tst ip, #8
+- movne r3, r7, lsr #8
++ movne r3, r7, pull #8
+ ldmneia r1!, {r4, r7}
+- orrne r3, r3, r4, lsl #24
+- movne r4, r4, lsr #8
+- orrne r4, r4, r7, lsl #24
++ orrne r3, r3, r4, push #24
++ movne r4, r4, pull #8
++ orrne r4, r4, r7, push #24
+ stmneia r0!, {r3 - r4} @ Shouldnt fault
+ tst ip, #4
+- movne r3, r7, lsr #8
++ movne r3, r7, pull #8
+ ldrne r7, [r1], #4
+- orrne r3, r3, r7, lsl #24
++ orrne r3, r3, r7, push #24
+ strnet r3, [r0], #4 @ Shouldnt fault
+ ands ip, ip, #3
+ beq .c2u_1fupi
+-.c2u_1nowords: mov r3, r7, lsr #8
++.c2u_1nowords: mov r3, r7, lsr #byte(1)
+ teq ip, #0
+ beq .c2u_finished
+ cmp ip, #2
+ USER( strbt r3, [r0], #1) @ May fault
+- movge r3, r3, lsr #8
++ movge r3, r7, lsr #byte(2)
+ USER( strgebt r3, [r0], #1) @ May fault
+- movgt r3, r3, lsr #8
++ movgt r3, r7, lsr #byte(3)
+ USER( strgtbt r3, [r0], #1) @ May fault
+ b .c2u_finished
+
+ .c2u_2fupi: subs r2, r2, #4
+ addmi ip, r2, #4
+ bmi .c2u_2nowords
+- mov r3, r7, lsr #16
++ mov r3, r7, pull #16
+ ldr r7, [r1], #4
+- orr r3, r3, r7, lsl #16
++ orr r3, r3, r7, push #16
+ USER( strt r3, [r0], #4) @ May fault
+ mov ip, r0, lsl #32 - PAGE_SHIFT
+ rsb ip, ip, #0
+@@ -182,39 +210,52 @@
+ sub r2, r2, ip
+ subs ip, ip, #16
+ blt .c2u_2rem8lp
++ PLD( pld [r1, #12] )
++ PLD( pld [r0, #12] )
++ PLD( subs ip, ip, #32 )
++ PLD( blt .c2u_2cpynopld )
++ PLD( pld [r1, #28] )
++ PLD( pld [r0, #28] )
+
+-.c2u_2cpy8lp: mov r3, r7, lsr #16
++.c2u_2cpy8lp:
++ PLD( pld [r1, #44] )
++ PLD( pld [r0, #44] )
++.c2u_2cpynopld: mov r3, r7, pull #16
+ ldmia r1!, {r4 - r7}
+- orr r3, r3, r4, lsl #16
+- mov r4, r4, lsr #16
+- orr r4, r4, r5, lsl #16
+- mov r5, r5, lsr #16
+- orr r5, r5, r6, lsl #16
+- mov r6, r6, lsr #16
+- orr r6, r6, r7, lsl #16
+- stmia r0!, {r3 - r6} @ Shouldnt fault
+ subs ip, ip, #16
++ orr r3, r3, r4, push #16
++ mov r4, r4, pull #16
++ orr r4, r4, r5, push #16
++ mov r5, r5, pull #16
++ orr r5, r5, r6, push #16
++ mov r6, r6, pull #16
++ orr r6, r6, r7, push #16
++ stmia r0!, {r3 - r6} @ Shouldnt fault
+ bpl .c2u_2cpy8lp
++ PLD( cmn ip, #32 )
++ PLD( bge .c2u_2cpynopld )
++ PLD( add ip, ip, #32 )
++
+ .c2u_2rem8lp: tst ip, #8
+- movne r3, r7, lsr #16
++ movne r3, r7, pull #16
+ ldmneia r1!, {r4, r7}
+- orrne r3, r3, r4, lsl #16
+- movne r4, r4, lsr #16
+- orrne r4, r4, r7, lsl #16
++ orrne r3, r3, r4, push #16
++ movne r4, r4, pull #16
++ orrne r4, r4, r7, push #16
+ stmneia r0!, {r3 - r4} @ Shouldnt fault
+ tst ip, #4
+- movne r3, r7, lsr #16
++ movne r3, r7, pull #16
+ ldrne r7, [r1], #4
+- orrne r3, r3, r7, lsl #16
++ orrne r3, r3, r7, push #16
+ strnet r3, [r0], #4 @ Shouldnt fault
+ ands ip, ip, #3
+ beq .c2u_2fupi
+-.c2u_2nowords: mov r3, r7, lsr #16
++.c2u_2nowords: mov r3, r7, lsr #byte(2)
+ teq ip, #0
+ beq .c2u_finished
+ cmp ip, #2
+ USER( strbt r3, [r0], #1) @ May fault
+- movge r3, r3, lsr #8
++ movge r3, r7, lsr #byte(3)
+ USER( strgebt r3, [r0], #1) @ May fault
+ ldrgtb r3, [r1], #0
+ USER( strgtbt r3, [r0], #1) @ May fault
+@@ -223,9 +264,9 @@
+ .c2u_3fupi: subs r2, r2, #4
+ addmi ip, r2, #4
+ bmi .c2u_3nowords
+- mov r3, r7, lsr #24
++ mov r3, r7, pull #24
+ ldr r7, [r1], #4
+- orr r3, r3, r7, lsl #8
++ orr r3, r3, r7, push #8
+ USER( strt r3, [r0], #4) @ May fault
+ mov ip, r0, lsl #32 - PAGE_SHIFT
+ rsb ip, ip, #0
+@@ -236,41 +277,54 @@
+ sub r2, r2, ip
+ subs ip, ip, #16
+ blt .c2u_3rem8lp
++ PLD( pld [r1, #12] )
++ PLD( pld [r0, #12] )
++ PLD( subs ip, ip, #32 )
++ PLD( blt .c2u_3cpynopld )
++ PLD( pld [r1, #28] )
++ PLD( pld [r0, #28] )
+
+-.c2u_3cpy8lp: mov r3, r7, lsr #24
++.c2u_3cpy8lp:
++ PLD( pld [r1, #44] )
++ PLD( pld [r0, #44] )
++.c2u_3cpynopld: mov r3, r7, pull #24
+ ldmia r1!, {r4 - r7}
+- orr r3, r3, r4, lsl #8
+- mov r4, r4, lsr #24
+- orr r4, r4, r5, lsl #8
+- mov r5, r5, lsr #24
+- orr r5, r5, r6, lsl #8
+- mov r6, r6, lsr #24
+- orr r6, r6, r7, lsl #8
+- stmia r0!, {r3 - r6} @ Shouldnt fault
+ subs ip, ip, #16
++ orr r3, r3, r4, push #8
++ mov r4, r4, pull #24
++ orr r4, r4, r5, push #8
++ mov r5, r5, pull #24
++ orr r5, r5, r6, push #8
++ mov r6, r6, pull #24
++ orr r6, r6, r7, push #8
++ stmia r0!, {r3 - r6} @ Shouldnt fault
+ bpl .c2u_3cpy8lp
++ PLD( cmn ip, #32 )
++ PLD( bge .c2u_3cpynopld )
++ PLD( add ip, ip, #32 )
++
+ .c2u_3rem8lp: tst ip, #8
+- movne r3, r7, lsr #24
++ movne r3, r7, pull #24
+ ldmneia r1!, {r4, r7}
+- orrne r3, r3, r4, lsl #8
+- movne r4, r4, lsr #24
+- orrne r4, r4, r7, lsl #8
++ orrne r3, r3, r4, push #8
++ movne r4, r4, pull #24
++ orrne r4, r4, r7, push #8
+ stmneia r0!, {r3 - r4} @ Shouldnt fault
+ tst ip, #4
+- movne r3, r7, lsr #24
++ movne r3, r7, pull #24
+ ldrne r7, [r1], #4
+- orrne r3, r3, r7, lsl #8
++ orrne r3, r3, r7, push #8
+ strnet r3, [r0], #4 @ Shouldnt fault
+ ands ip, ip, #3
+ beq .c2u_3fupi
+-.c2u_3nowords: mov r3, r7, lsr #24
++.c2u_3nowords: mov r3, r7, lsr #byte(3)
+ teq ip, #0
+ beq .c2u_finished
+ cmp ip, #2
+ USER( strbt r3, [r0], #1) @ May fault
+- ldrge r3, [r1], #0
++ ldrgeb r3, [r1], #1
+ USER( strgebt r3, [r0], #1) @ May fault
+- movgt r3, r3, lsr #8
++ ldrgtb r3, [r1], #0
+ USER( strgtbt r3, [r0], #1) @ May fault
+ b .c2u_finished
+
+@@ -302,6 +356,8 @@
+ stmfd sp!, {r0, r2, r4 - r7, lr}
+ cmp r2, #4
+ blt .cfu_not_enough
++ PLD( pld [r1, #0] )
++ PLD( pld [r0, #0] )
+ ands ip, r0, #3
+ bne .cfu_dest_not_aligned
+ .cfu_dest_aligned:
+@@ -329,13 +385,26 @@
+ sub r2, r2, ip
+ subs ip, ip, #32
+ blt .cfu_0rem8lp
++ PLD( pld [r1, #28] )
++ PLD( pld [r0, #28] )
++ PLD( subs ip, ip, #64 )
++ PLD( blt .cfu_0cpynopld )
++ PLD( pld [r1, #60] )
++ PLD( pld [r0, #60] )
+
+-.cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault
++.cfu_0cpy8lp:
++ PLD( pld [r1, #92] )
++ PLD( pld [r0, #92] )
++.cfu_0cpynopld: ldmia r1!, {r3 - r6} @ Shouldnt fault
+ stmia r0!, {r3 - r6}
+ ldmia r1!, {r3 - r6} @ Shouldnt fault
+- stmia r0!, {r3 - r6}
+ subs ip, ip, #32
++ stmia r0!, {r3 - r6}
+ bpl .cfu_0cpy8lp
++ PLD( cmn ip, #64 )
++ PLD( bge .cfu_0cpynopld )
++ PLD( add ip, ip, #64 )
++
+ .cfu_0rem8lp: cmn ip, #16
+ ldmgeia r1!, {r3 - r6} @ Shouldnt fault
+ stmgeia r0!, {r3 - r6}
+@@ -374,9 +443,9 @@
+ .cfu_1fupi: subs r2, r2, #4
+ addmi ip, r2, #4
+ bmi .cfu_1nowords
+- mov r3, r7, lsr #8
++ mov r3, r7, pull #8
+ USER( ldrt r7, [r1], #4) @ May fault
+- orr r3, r3, r7, lsl #24
++ orr r3, r3, r7, push #24
+ str r3, [r0], #4
+ mov ip, r1, lsl #32 - PAGE_SHIFT
+ rsb ip, ip, #0
+@@ -387,50 +456,63 @@
+ sub r2, r2, ip
+ subs ip, ip, #16
+ blt .cfu_1rem8lp
++ PLD( pld [r1, #12] )
++ PLD( pld [r0, #12] )
++ PLD( subs ip, ip, #32 )
++ PLD( blt .cfu_1cpynopld )
++ PLD( pld [r1, #28] )
++ PLD( pld [r0, #28] )
+
+-.cfu_1cpy8lp: mov r3, r7, lsr #8
++.cfu_1cpy8lp:
++ PLD( pld [r1, #44] )
++ PLD( pld [r0, #44] )
++.cfu_1cpynopld: mov r3, r7, pull #8
+ ldmia r1!, {r4 - r7} @ Shouldnt fault
+- orr r3, r3, r4, lsl #24
+- mov r4, r4, lsr #8
+- orr r4, r4, r5, lsl #24
+- mov r5, r5, lsr #8
+- orr r5, r5, r6, lsl #24
+- mov r6, r6, lsr #8
+- orr r6, r6, r7, lsl #24
+- stmia r0!, {r3 - r6}
+ subs ip, ip, #16
++ orr r3, r3, r4, push #24
++ mov r4, r4, pull #8
++ orr r4, r4, r5, push #24
++ mov r5, r5, pull #8
++ orr r5, r5, r6, push #24
++ mov r6, r6, pull #8
++ orr r6, r6, r7, push #24
++ stmia r0!, {r3 - r6}
+ bpl .cfu_1cpy8lp
++ PLD( cmn ip, #32 )
++ PLD( bge .cfu_1cpynopld )
++ PLD( add ip, ip, #32 )
++
+ .cfu_1rem8lp: tst ip, #8
+- movne r3, r7, lsr #8
++ movne r3, r7, pull #8
+ ldmneia r1!, {r4, r7} @ Shouldnt fault
+- orrne r3, r3, r4, lsl #24
+- movne r4, r4, lsr #8
+- orrne r4, r4, r7, lsl #24
++ orrne r3, r3, r4, push #24
++ movne r4, r4, pull #8
++ orrne r4, r4, r7, push #24
+ stmneia r0!, {r3 - r4}
+ tst ip, #4
+- movne r3, r7, lsr #8
++ movne r3, r7, pull #8
+ USER( ldrnet r7, [r1], #4) @ May fault
+- orrne r3, r3, r7, lsl #24
++ orrne r3, r3, r7, push #24
+ strne r3, [r0], #4
+ ands ip, ip, #3
+ beq .cfu_1fupi
+-.cfu_1nowords: mov r3, r7, lsr #8
++.cfu_1nowords: mov r3, r7, lsr #byte(1)
+ teq ip, #0
+ beq .cfu_finished
+ cmp ip, #2
+ strb r3, [r0], #1
+- movge r3, r3, lsr #8
++ movge r3, r7, lsr #byte(2)
+ strgeb r3, [r0], #1
+- movgt r3, r3, lsr #8
++ movgt r3, r7, lsr #byte(3)
+ strgtb r3, [r0], #1
+ b .cfu_finished
+
+ .cfu_2fupi: subs r2, r2, #4
+ addmi ip, r2, #4
+ bmi .cfu_2nowords
+- mov r3, r7, lsr #16
++ mov r3, r7, pull #16
+ USER( ldrt r7, [r1], #4) @ May fault
+- orr r3, r3, r7, lsl #16
++ orr r3, r3, r7, push #16
+ str r3, [r0], #4
+ mov ip, r1, lsl #32 - PAGE_SHIFT
+ rsb ip, ip, #0
+@@ -441,39 +523,52 @@
+ sub r2, r2, ip
+ subs ip, ip, #16
+ blt .cfu_2rem8lp
++ PLD( pld [r1, #12] )
++ PLD( pld [r0, #12] )
++ PLD( subs ip, ip, #32 )
++ PLD( blt .cfu_2cpynopld )
++ PLD( pld [r1, #28] )
++ PLD( pld [r0, #28] )
+
+-.cfu_2cpy8lp: mov r3, r7, lsr #16
++.cfu_2cpy8lp:
++ PLD( pld [r1, #44] )
++ PLD( pld [r0, #44] )
++.cfu_2cpynopld: mov r3, r7, pull #16
+ ldmia r1!, {r4 - r7} @ Shouldnt fault
+- orr r3, r3, r4, lsl #16
+- mov r4, r4, lsr #16
+- orr r4, r4, r5, lsl #16
+- mov r5, r5, lsr #16
+- orr r5, r5, r6, lsl #16
+- mov r6, r6, lsr #16
+- orr r6, r6, r7, lsl #16
+- stmia r0!, {r3 - r6}
+ subs ip, ip, #16
++ orr r3, r3, r4, push #16
++ mov r4, r4, pull #16
++ orr r4, r4, r5, push #16
++ mov r5, r5, pull #16
++ orr r5, r5, r6, push #16
++ mov r6, r6, pull #16
++ orr r6, r6, r7, push #16
++ stmia r0!, {r3 - r6}
+ bpl .cfu_2cpy8lp
++ PLD( cmn ip, #32 )
++ PLD( bge .cfu_2cpynopld )
++ PLD( add ip, ip, #32 )
++
+ .cfu_2rem8lp: tst ip, #8
+- movne r3, r7, lsr #16
++ movne r3, r7, pull #16
+ ldmneia r1!, {r4, r7} @ Shouldnt fault
+- orrne r3, r3, r4, lsl #16
+- movne r4, r4, lsr #16
+- orrne r4, r4, r7, lsl #16
++ orrne r3, r3, r4, push #16
++ movne r4, r4, pull #16
++ orrne r4, r4, r7, push #16
+ stmneia r0!, {r3 - r4}
+ tst ip, #4
+- movne r3, r7, lsr #16
++ movne r3, r7, pull #16
+ USER( ldrnet r7, [r1], #4) @ May fault
+- orrne r3, r3, r7, lsl #16
++ orrne r3, r3, r7, push #16
+ strne r3, [r0], #4
+ ands ip, ip, #3
+ beq .cfu_2fupi
+-.cfu_2nowords: mov r3, r7, lsr #16
++.cfu_2nowords: mov r3, r7, lsr #byte(2)
+ teq ip, #0
+ beq .cfu_finished
+ cmp ip, #2
+ strb r3, [r0], #1
+- movge r3, r3, lsr #8
++ movge r3, r7, lsr #byte(3)
+ strgeb r3, [r0], #1
+ USER( ldrgtbt r3, [r1], #0) @ May fault
+ strgtb r3, [r0], #1
+@@ -482,9 +577,9 @@
+ .cfu_3fupi: subs r2, r2, #4
+ addmi ip, r2, #4
+ bmi .cfu_3nowords
+- mov r3, r7, lsr #24
++ mov r3, r7, pull #24
+ USER( ldrt r7, [r1], #4) @ May fault
+- orr r3, r3, r7, lsl #8
++ orr r3, r3, r7, push #8
+ str r3, [r0], #4
+ mov ip, r1, lsl #32 - PAGE_SHIFT
+ rsb ip, ip, #0
+@@ -495,41 +590,54 @@
+ sub r2, r2, ip
+ subs ip, ip, #16
+ blt .cfu_3rem8lp
++ PLD( pld [r1, #12] )
++ PLD( pld [r0, #12] )
++ PLD( subs ip, ip, #32 )
++ PLD( blt .cfu_3cpynopld )
++ PLD( pld [r1, #28] )
++ PLD( pld [r0, #28] )
+
+-.cfu_3cpy8lp: mov r3, r7, lsr #24
++.cfu_3cpy8lp:
++ PLD( pld [r1, #44] )
++ PLD( pld [r0, #44] )
++.cfu_3cpynopld: mov r3, r7, pull #24
+ ldmia r1!, {r4 - r7} @ Shouldnt fault
+- orr r3, r3, r4, lsl #8
+- mov r4, r4, lsr #24
+- orr r4, r4, r5, lsl #8
+- mov r5, r5, lsr #24
+- orr r5, r5, r6, lsl #8
+- mov r6, r6, lsr #24
+- orr r6, r6, r7, lsl #8
++ orr r3, r3, r4, push #8
++ mov r4, r4, pull #24
++ orr r4, r4, r5, push #8
++ mov r5, r5, pull #24
++ orr r5, r5, r6, push #8
++ mov r6, r6, pull #24
++ orr r6, r6, r7, push #8
+ stmia r0!, {r3 - r6}
+ subs ip, ip, #16
+ bpl .cfu_3cpy8lp
++ PLD( cmn ip, #32 )
++ PLD( bge .cfu_3cpynopld )
++ PLD( add ip, ip, #32 )
++
+ .cfu_3rem8lp: tst ip, #8
+- movne r3, r7, lsr #24
++ movne r3, r7, pull #24
+ ldmneia r1!, {r4, r7} @ Shouldnt fault
+- orrne r3, r3, r4, lsl #8
+- movne r4, r4, lsr #24
+- orrne r4, r4, r7, lsl #8
++ orrne r3, r3, r4, push #8
++ movne r4, r4, pull #24
++ orrne r4, r4, r7, push #8
+ stmneia r0!, {r3 - r4}
+ tst ip, #4
+- movne r3, r7, lsr #24
++ movne r3, r7, pull #24
+ USER( ldrnet r7, [r1], #4) @ May fault
+- orrne r3, r3, r7, lsl #8
++ orrne r3, r3, r7, push #8
+ strne r3, [r0], #4
+ ands ip, ip, #3
+ beq .cfu_3fupi
+-.cfu_3nowords: mov r3, r7, lsr #24
++.cfu_3nowords: mov r3, r7, lsr #byte(3)
+ teq ip, #0
+ beq .cfu_finished
+ cmp ip, #2
+ strb r3, [r0], #1
+-USER( ldrget r3, [r1], #0) @ May fault
++USER( ldrgebt r3, [r1], #1) @ May fault
+ strgeb r3, [r0], #1
+- movgt r3, r3, lsr #8
++USER( ldrgtbt r3, [r1], #1) @ May fault
+ strgtb r3, [r0], #1
+ b .cfu_finished
+
+@@ -544,7 +652,7 @@
+ ldr r1, [sp], #4 @ unsigned long count
+ subs r4, r1, r2 @ bytes left to copy
+ movne r1, r4
+- blne SYMBOL_NAME(__memzero)
++ blne __memzero
+ mov r0, r4
+ LOADREGS(fd,sp!, {r4 - r7, pc})
+ .previous
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/Makefile
+@@ -0,0 +1,56 @@
++#
++# Makefile for the linux kernel.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++USE_STANDARD_AS_RULE := true
++
++O_TARGET := pxa.o
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj- :=
++
++export-objs := generic.o irq.o dma.o sa1111.o \
++ usb_ctl.o usb_recv.o usb_send.o
++
++# Common support (must be linked before board specific support)
++obj-y += generic.o irq.o dma.o
++obj-$(CONFIG_SA1111) += sa1111.o
++
++# Specific board support
++obj-$(CONFIG_ARCH_CSB226) += csb226.o
++obj-$(CONFIG_ARCH_INNOKOM) += innokom.o
++obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
++obj-$(CONFIG_ARCH_PXA_CERF) += cerf.o
++obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
++obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o
++
++# Support for blinky lights
++leds-y := leds.o
++leds-$(CONFIG_ARCH_CSB226) += leds-csb226.o
++leds-$(CONFIG_ARCH_INNOKOM) += leds-innokom.o
++leds-$(CONFIG_ARCH_LUBBOCK) += leds-lubbock.o
++leds-$(CONFIG_ARCH_PXA_IDP) += leds-idp.o
++leds-$(CONFIG_ARCH_PXA_CERF) += leds-cerf.o
++
++obj-$(CONFIG_LEDS) += $(leds-y)
++
++# PXA USB client support
++list-multi += pxausb_core.o
++pxausb_core-objs := usb_ctl.o usb_ep0.o usb_recv.o usb_send.o
++obj-$(CONFIG_PXA_USB) += pxausb_core.o
++obj-$(CONFIG_PXA_USB_NETLINK) += usb-eth.o
++obj-$(CONFIG_PXA_USB_CHAR) += usb-char.o
++
++# Misc features
++obj-$(CONFIG_PM) += pm.o sleep.o
++obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o
++
++include $(TOPDIR)/Rules.make
++
++pxausb_core.o: $(pxausb_core-objs)
++ $(LD) -r -o $@ $(pxausb_core-objs)
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/cerf.c
+@@ -0,0 +1,266 @@
++/*
++ * linux/arch/arm/mach-pxa/cerf.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/init.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/io.h>
++#include <asm/arch/irq.h>
++
++#include "generic.h"
++
++/*
++ * Set this to zero to remove all the debug statements via
++ * dead code elimination.
++ */
++#define DEBUGGING 1
++
++#if DEBUGGING
++static unsigned int cerf_debug = DEBUGGING;
++#else
++#define cerf_debug 0
++#endif
++
++static void __init cerf_init_irq(void)
++{
++ pxa_init_irq();
++
++ if( cerf_debug > 1)
++ {
++#if 0
++ GPDR0 = 0xc05b9130;
++ GPDR1 = 0xfcffab82;
++ GPDR2 = 0x0001ffff;
++#endif
++
++ printk(KERN_INFO "Pin directions:\n");
++ printk(KERN_INFO "GPDR0 0x%08x\n", GPDR0);
++ printk(KERN_INFO "GPDR1 0x%08x\n", GPDR1);
++ printk(KERN_INFO "GPDR2 0x%08x\n", GPDR2);
++
++ printk(KERN_INFO "Pin State:\n");
++ printk(KERN_INFO "GPLR0 0x%08x\n", GPLR0);
++ printk(KERN_INFO "GPLR1 0x%08x\n", GPLR1);
++ printk(KERN_INFO "GPLR2 0x%08x\n", GPLR2);
++
++ printk(KERN_INFO "Rising Edge:\n");
++ printk(KERN_INFO "GRER0 0x%08x\n", GRER0);
++ printk(KERN_INFO "GRER1 0x%08x\n", GRER1);
++ printk(KERN_INFO "GRER2 0x%08x\n", GRER2);
++
++ printk(KERN_INFO "Falling Edge:\n");
++ printk(KERN_INFO "GFER0 0x%08x\n", GFER0);
++ printk(KERN_INFO "GFER1 0x%08x\n", GFER1);
++ printk(KERN_INFO "GFER2 0x%08x\n", GFER2);
++ }
++
++ /* set_GPIO_IRQ_edge has to be called before an irq can be requested */
++ set_GPIO_IRQ_edge( 0, GPIO_FALLING_EDGE); /* CPLD */
++#ifdef CONFIG_PXA_CERF_PDA
++ set_GPIO_IRQ_edge( 2, GPIO_RISING_EDGE); /* UART B Interrupt */
++ set_GPIO_IRQ_edge( 3, GPIO_RISING_EDGE); /* UART A Interrupt */
++ set_GPIO_IRQ_edge( 32, GPIO_RISING_EDGE); /* UCB1400 Interrupt */
++#endif
++ set_GPIO_IRQ_edge( 14, GPIO_FALLING_EDGE); /* PCMCIA Card Detect */
++ set_GPIO_IRQ_edge( 21, GPIO_RISING_EDGE); /* Ethernet Interrupt */
++}
++
++static int __init cerf_init(void)
++{
++ /*
++ * All of the code that was here was SA1111 init code
++ * which we do not have.
++ */
++ return 0;
++}
++
++__initcall(cerf_init);
++
++static void __init
++fixup_cerf(struct machine_desc *desc, struct param_struct *params,
++ char **cmdline, struct meminfo *mi)
++{
++ SET_BANK (0, CERF_RAM_BASE, CERF_RAM_SIZE);
++ mi->nr_banks = 1;
++
++#if 0 // Enable this stuff if you plan on not using jffs2
++ setup_ramdisk (1, 0, 0, 8192);
++ setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024);
++ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
++#endif
++}
++
++/*
++ * IO map for the devices.
++ */
++static struct map_desc cerf_io_desc[] __initdata = {
++ /* virtual physical length domain r w c b */
++ { CERF_FLASH_BASE , CERF_FLASH_PHYS , CERF_FLASH_SIZE , DOMAIN_IO, 0, 1, 0, 0 },
++ { CERF_ETH_BASE , CERF_ETH_PHYS , CERF_ETH_SIZE , DOMAIN_IO, 0, 1, 0, 0 },
++#ifdef CONFIG_PXA_CERF_PDA
++ { CERF_BT_BASE , CERF_BT_PHYS , CERF_BT_SIZE , DOMAIN_IO, 0, 1, 0, 0 },
++ { CERF_SERIAL_BASE, CERF_SERIAL_PHYS, CERF_SERIAL_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
++ { CERF_CPLD_BASE , CERF_CPLD_PHYS , CERF_CPLD_SIZE , DOMAIN_IO, 0, 1, 0, 0 },
++#endif
++
++ LAST_DESC
++};
++
++static void __init cerf_map_io(void)
++{
++ pxa_map_io();
++ iotable_init(cerf_io_desc);
++
++ if( cerf_debug > 1)
++ {
++ printk(KERN_INFO "origMCS0 = 0x%08x\n", MSC0);
++ printk(KERN_INFO "origMCS1 = 0x%08x\n", MSC1);
++ printk(KERN_INFO "origMCS2 = 0x%08x\n", MSC2);
++ }
++
++ /* setup memory timing for CS0/1 */
++ MSC0 = MSC_CS(0, MSC_RBUFF(MSC_RBUFF_SLOW) |
++ MSC_RRR(3) |
++ MSC_RDN(15) |
++ MSC_RDF(13) |
++ MSC_RBW(0) |
++ MSC_RT(0)) |
++#ifdef CONFIG_PXA_CERF_PDA
++ MSC_CS(1, MSC_RBUFF(MSC_RBUFF_SLOW) |
++ MSC_RRR(7) |
++ MSC_RDN(15) |
++ MSC_RDF(15) |
++ MSC_RBW(1) |
++ MSC_RT(0));
++#elif defined(CONFIG_PXA_CERF_BOARD)
++ MSC_CS(1, MSC_RBUFF(MSC_RBUFF_SLOW) |
++ MSC_RRR(1) |
++ MSC_RDN(2) |
++ MSC_RDF(4) |
++ MSC_RBW(0) |
++ MSC_RT(4));
++#endif
++ printk(KERN_INFO "MCS0 = 0x%08x\n", MSC0);
++
++ /* setup memory timing for CS2/3 */
++ MSC1 = MSC_CS(2, MSC_RBUFF(MSC_RBUFF_SLOW) |
++ MSC_RRR(5) |
++ MSC_RDN(10) |
++ MSC_RDF(10) |
++ MSC_RBW(1) |
++ MSC_RT(0)) |
++ MSC_CS(3, MSC_RBUFF(MSC_RBUFF_SLOW) |
++ MSC_RRR(5) |
++ MSC_RDN(10) |
++ MSC_RDF(10) |
++ MSC_RBW(1) |
++ MSC_RT(0));
++ printk(KERN_INFO "MCS1 = 0x%08x\n", MSC1);
++
++ /* setup memory timing for CS4/5 */
++ MSC2 = MSC_CS(4, MSC_RBUFF(MSC_RBUFF_SLOW) |
++ MSC_RRR(2) |
++ MSC_RDN(4) |
++ MSC_RDF(4) |
++ MSC_RBW(1) |
++ MSC_RT(0)) |
++ MSC_CS(5, MSC_RBUFF(MSC_RBUFF_SLOW) |
++ MSC_RRR(2) |
++ MSC_RDN(4) |
++ MSC_RDF(4) |
++ MSC_RBW(1) |
++ MSC_RT(0));
++ printk(KERN_INFO "MCS2 = 0x%08x\n", MSC2);
++
++#ifdef CONFIG_SOUND_PXA_AC97
++ printk(KERN_INFO "Enabling sound amp for pxa cerf pda.\n");
++ outw( CERF_PDA_SOUND_ENABLE, CERF_CPLD_BASE+CERF_PDA_CPLD_SOUND_ENA);
++#endif
++
++#ifdef CONFIG_FB_PXA
++ printk(KERN_INFO "Setting LCD to brightness to %d/15\n", CERF_PDA_DEFAULT_BRIGHTNESS);
++ outw( CERF_PDA_DEFAULT_BRIGHTNESS, CERF_CPLD_BASE+CERF_PDA_CPLD_BRIGHTNESS);
++#endif
++
++#ifdef CONFIG_IRDA
++ /* Enable IrDA UART (SIR)*/
++ CKEN |= CKEN5_STUART;
++
++ /* We want to get our goods from the STUART */
++ set_GPIO_mode(GPIO46_STRXD_MD);
++ set_GPIO_mode(GPIO47_STTXD_MD);
++
++ /* make sure FIR ICP is off */
++ ICCR0 = 0;
++
++ /* configure STUART to for SIR
++ * NOTE: RCVEIR and XMITIR must not be set at the same time!
++ * Start with receive in IR mode, and switch transmit to IR only
++ * when we need to send something in serial driver.
++ */
++ STISR = IrSR_IR_RECEIVE_ON;
++#endif
++
++#if 0
++ /* Connect FIR ICP to GPIO pins */
++ CKEN |= CKEN13_FICP;
++ set_GPIO_mode(GPIO46_ICPRXD_MD);
++ set_GPIO_mode(GPIO47_ICPTXD_MD);
++ ICCR0 = 0x1 | 0x18; //ICP unit enable
++#endif
++
++#if 0
++ /* Enable BT UART */
++ CKEN |= CKEN7_BTUART;
++ set_GPIO_mode(GPIO42_BTRXD_MD);
++ set_GPIO_mode(GPIO43_BTTXD_MD);
++ set_GPIO_mode(GPIO44_BTCTS_MD);
++ set_GPIO_mode(GPIO45_BTRTS_MD);
++#endif
++
++ if( cerf_debug > 1)
++ {
++ printk(KERN_INFO "GPDR0 0x%08x\n", GPDR0);
++ printk(KERN_INFO "GPDR1 0x%08x\n", GPDR1);
++ printk(KERN_INFO "GPDR2 0x%08x\n", GPDR2);
++ printk(KERN_INFO "GPLR0 0x%08x\n", GPLR0);
++ printk(KERN_INFO "GPLR1 0x%08x\n", GPLR1);
++ printk(KERN_INFO "GPLR2 0x%08x\n", GPLR2);
++ printk(KERN_INFO "GAFR0_L 0x%08x\n", GAFR0_L);
++ printk(KERN_INFO "GAFR0_U 0x%08x\n", GAFR0_U);
++ printk(KERN_INFO "GAFR1_L 0x%08x\n", GAFR1_L);
++ printk(KERN_INFO "GAFR1_U 0x%08x\n", GAFR1_U);
++ printk(KERN_INFO "GAFR2_L 0x%08x\n", GAFR2_L);
++ printk(KERN_INFO "GAFR2_U 0x%08x\n", GAFR2_U);
++ printk(KERN_INFO "CKEN = 0x%08x\n", CKEN);
++ printk(KERN_INFO "ICCR0 = 0x%08x\n", ICCR0);
++ printk(KERN_INFO "STISR = 0x%08x\n", STISR);
++ }
++}
++
++MACHINE_START(PXA_CERF, "CerfBoard PXA Reference Board")
++ MAINTAINER("Intrinsyc Software Inc.")
++ BOOT_MEM(0xa0000000, 0x40000000, 0xfc000000)
++ BOOT_PARAMS(0xa0000100)
++ FIXUP(fixup_cerf)
++ MAPIO(cerf_map_io)
++ INITIRQ(cerf_init_irq)
++MACHINE_END
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/cpu-pxa.c
+@@ -0,0 +1,240 @@
++/*
++ * linux/arch/arm/mach-pxa/cpu-pxa.c
++ *
++ * Copyright (C) 2002,2003 Intrinsyc Software
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * History:
++ * 31-Jul-2002 : Initial version [FB]
++ * 29-Jan-2003 : added PXA255 support [FB]
++ *
++ * Note:
++ *
++ * Quote from erratum 134:
++ * ""If the operation of these peripherals would be adversely affected,
++ * then these peripherals would have to be disabled during a frequency
++ * change. (MMC,FFUART,STUART,BTUART,IRDA,SSP,UDC,AC97)""
++ *
++ * This sounds like they are not sure what the bug is...
++ * If you run into problems with any of these peripherals, the effected
++ * driver should register with cpu freq notification and disable/enable
++ * the peripheral on CPUFREQ_PRECHANGE and CPUFREQ_POSTCHANGE.
++ *
++ * So far I've tested this code only under light load. It works for me.
++ *
++ * TODO:
++ * - determine min/max freq at runtime
++ * - determine pxbus value at runtime
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/cpufreq.h>
++
++#include <asm/hardware.h>
++
++#define DEBUGGING 1
++
++#if DEBUGGING
++static unsigned int freq_debug = DEBUGGING;
++#else
++#define freq_debug 0
++#endif
++
++typedef struct
++{
++ unsigned int khz;
++ unsigned int cccr;
++ unsigned int pxbus;
++} pxa_freqs_t;
++
++#define CCLKCFG_TURBO 0x1
++#define CCLKCFG_FCS 0x2
++
++#define PXA250_REV_A1 0x1
++#define PXA250_REV_B2 0x4
++#define PXA25x_MIN_FREQ 99000
++
++//#define PXA25x_ALLOW_OVERCLOCK
++
++#ifdef PXA25x_ALLOW_OVERCLOCK
++#warning *** Overclocking enabled - this may fry your hardware - you have been warned ***
++#define OC(x...) x
++#define PXA25x_MAX_FREQ 471000
++#else
++#define OC(x...)
++#define PXA25x_MAX_FREQ 400000
++#endif
++
++/* If CONFIG_CPU_FREQ is turned on but we find (at runtime)
++ * we can't support scaling, try to handle requests gracefully.
++ */
++static int supported;
++
++static pxa_freqs_t pxa250_valid_freqs[] =
++{
++ {199100, 0x141, 99}, /* mem= 99, run=199, turbo=199, PXbus= 99 */
++ {298600, 0x1c1, 99}, /* mem= 99, run=199, turbo=298, PXbus= 99 */
++ {398100, 0x241, 99}, /* mem= 99, run=199, turbo=398, PXbus= 99 */
++ {0,0}
++};
++
++static pxa_freqs_t pxa255_valid_freqs[] =
++{
++ { 99000, 0x121, 50}, /* mem= 99, run= 99, turbo= 99, PXbus= 50 */
++OC( {118000, 0x122, 59},)/* mem=118, run=118, turbo=118, PXbus= 59 OC'd mem */
++ {199100, 0x141, 99}, /* mem= 99, run=199, turbo=199, PXbus= 99 */
++OC( {236000, 0x142,118},)/* mem=118, run=236, turbo=236, PXbus=118 OC'd mem */
++ {298600, 0x1c1, 99}, /* mem= 99, run=199, turbo=298, PXbus= 99 */
++OC( {354000, 0x1c2,118},)/* mem=118, run=236, turbo=354, PXbus=118 OC'd mem */
++ {398099, 0x241, 99}, /* mem= 99, run=199, turbo=398, PXbus= 99 */
++ {398100, 0x161,196}, /* mem= 99, run=398, turbo=398, PXbus=196 */
++OC( {471000, 0x162,236},)/* mem=118, run=471, turbo=471, PXbus=236 OC'd mem/core/bus */
++ {0,0}
++};
++
++static pxa_freqs_t *pxa_valid_freqs;
++
++/* This should be called with a valid freq point that was
++ * obtained via pxa_validate_speed
++ */
++static pxa_freqs_t * pxa_get_freq_info( unsigned int khz)
++{
++ int i=0;
++ while( pxa_valid_freqs[i].khz)
++ {
++ if( pxa_valid_freqs[i].khz == khz)
++ return &pxa_valid_freqs[i];
++ i++;
++ }
++
++ /* shouldn't get here */
++ return 0;
++}
++
++/* find a valid frequency point */
++static unsigned int pxa_validate_speed(unsigned int khz)
++{
++ int i=0;
++ unsigned int vfreq = 0;
++ while( pxa_valid_freqs[i].khz && (khz >= pxa_valid_freqs[i].khz))
++ {
++ vfreq = pxa_valid_freqs[i].khz;
++ i++;
++ }
++ return vfreq;
++}
++
++/* This should be called with a valid freq point that was
++ * obtained via pxa_validate_speed
++ */
++static void pxa_setspeed(unsigned int khz)
++{
++ unsigned long flags;
++ unsigned int unused;
++ void *ramstart = phys_to_virt(0xa0000000);
++ pxa_freqs_t *freq_info;
++
++ if( ! supported) return;
++
++ freq_info = pxa_get_freq_info( khz);
++
++ if( ! freq_info) return;
++
++ CCCR = freq_info->cccr;
++ if( freq_debug)
++ printk(KERN_INFO "Changing CPU frequency to %d Mhz (PXbus=%dMhz).\n",
++ khz/1000, freq_info->pxbus);
++
++ local_irq_save(flags);
++ __asm__ __volatile__("\
++ ldr r4, [%1] @load MDREFR \n\
++ b 2f \n\
++ .align 5 \n\
++1: \n\
++ mcr p14, 0, %2, c6, c0, 0 @ set CCLKCFG[FCS] \n\
++ \n\
++ @ restart sdcke 0 / 1 \n\
++ bic r5, r4, #(0x00001000 | 0x00008000) @ MDREFR_E0PIN | MDREFR_E1PIN \n\
++ str r5, [%1] @clear \n\
++ str r4, [%1] @restore \n\
++ \n\
++ @ Generate refresh cycles for all banks \n\
++ ldr r4, [%3] \n\
++ str r4, [%3] \n\
++ str r4, [%3] \n\
++ str r4, [%3] \n\
++ str r4, [%3] \n\
++ str r4, [%3] \n\
++ str r4, [%3] \n\
++ str r4, [%3] \n\
++ str r4, [%3] \n\
++ \n\
++ b 3f \n\
++2: b 1b \n\
++3: nop \n\
++ "
++ : "=&r" (unused)
++ : "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart)
++ : "r4", "r5");
++ local_irq_restore(flags);
++}
++
++static int pxa_init_freqs( void)
++{
++ int cpu_ver;
++ asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver));
++
++ if( (cpu_ver & 0xf) <= PXA250_REV_A1)
++ {
++ return 0;
++ }
++
++ if( (cpu_ver & 0xf) <= PXA250_REV_B2)
++ {
++ if( freq_debug) printk(KERN_INFO "Using PXA250 frequency points.\n");
++ pxa_valid_freqs = pxa250_valid_freqs;
++ }
++ else /* C0 and above */
++ {
++ if( freq_debug) printk(KERN_INFO "Using PXA255 frequency points.\n");
++ pxa_valid_freqs = pxa255_valid_freqs;
++ }
++
++ return 1;
++}
++
++static int __init pxa_clk_init(void)
++{
++ if( pxa_init_freqs())
++ {
++ if( freq_debug) printk(KERN_INFO "Registering CPU frequency change support.\n");
++ supported = 1;
++
++ cpufreq_init( get_clk_frequency_khz(0), PXA25x_MIN_FREQ, PXA25x_MAX_FREQ);
++ cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed);
++ }
++ else
++ {
++ if( freq_debug) printk(KERN_INFO "Disabling CPU frequency change support.\n");
++ /* Note that we have to initialize the generic code in order to
++ * release a lock (cpufreq_sem). Any registration for freq changes
++ * (e.g. lcd driver) will get blocked otherwise.
++ */
++ cpufreq_init( 0, 0, 0);
++ cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed);
++ }
++
++ return 0;
++}
++
++module_init(pxa_clk_init);
++
++MODULE_AUTHOR ("Intrinsyc Software Inc.");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/csb226.c
+@@ -0,0 +1,180 @@
++/*
++ * linux/arch/arm/mach-pxa/csb226.c
++ *
++ * (c) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/init.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/arch/irq.h>
++#include <asm/arch/irqs.h>
++#include <asm/hardware/sa1111.h>
++
++#include "generic.h"
++
++static unsigned long csb226_irq_en_mask;
++
++static void csb226_mask_and_ack_irq(unsigned int irq)
++{
++ int csb226_irq = (irq - CSB226_IRQ(0));
++ csb226_irq_en_mask &= ~(1 << csb226_irq);
++ CSB226_IRQ_MASK_EN &= ~(1 << csb226_irq);
++ CSB226_IRQ_SET_CLR &= ~(1 << csb226_irq);
++}
++
++static void csb226_mask_irq(unsigned int irq)
++{
++ int csb226_irq = (irq - CSB226_IRQ(0));
++ csb226_irq_en_mask &= ~(1 << csb226_irq);
++ CSB226_IRQ_MASK_EN &= ~(1 << csb226_irq);
++}
++
++static void csb226_unmask_irq(unsigned int irq)
++{
++ int csb226_irq = (irq - CSB226_IRQ(0));
++ csb226_irq_en_mask |= (1 << csb226_irq);
++ CSB226_IRQ_MASK_EN |= (1 << csb226_irq);
++}
++
++void csb226_irq_demux(int irq, void *dev_id, struct pt_regs *regs)
++{
++ unsigned long irq_status;
++ int i;
++
++ while ((irq_status = CSB226_IRQ_SET_CLR & csb226_irq_en_mask)) {
++ for (i = 0; i < 6; i++) {
++ if(irq_status & (1<<i))
++ do_IRQ(CSB226_IRQ(i), regs);
++ }
++ }
++}
++
++/* FIXME: this should not be necessary on csb226 */
++static struct irqaction csb226_irq = {
++ name: "CSB226 FPGA",
++ handler: csb226_irq_demux,
++ flags: SA_INTERRUPT
++};
++
++static void __init csb226_init_irq(void)
++{
++ int irq;
++
++ pxa_init_irq();
++
++ /* setup extra csb226 irqs */
++/* RS: ???
++ for(irq = CSB226_IRQ(0); irq <= CSB226_IRQ(5); irq++)
++ {
++ irq_desc[irq].valid = 1;
++ irq_desc[irq].probe_ok = 1;
++ irq_desc[irq].mask_ack = csb226_mask_and_ack_irq;
++ irq_desc[irq].mask = csb226_mask_irq;
++ irq_desc[irq].unmask = csb226_unmask_irq;
++ }
++
++ set_GPIO_IRQ_edge(GPIO_CSB226_IRQ, GPIO_FALLING_EDGE);
++ setup_arm_irq(IRQ_GPIO_CSB226_IRQ, &csb226_irq);
++*/
++}
++
++/* FIXME: not necessary on CSB226? */
++static int __init csb226_init(void)
++{
++ int ret;
++
++ return 0;
++}
++
++__initcall(csb226_init);
++
++static void __init
++fixup_csb226(struct machine_desc *desc, struct param_struct *params,
++ char **cmdline, struct meminfo *mi)
++{
++ SET_BANK (0, 0xa0000000, 64*1024*1024);
++ mi->nr_banks = 1;
++#if 0
++ setup_ramdisk (1, 0, 0, 8192);
++ setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024);
++ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
++#endif
++}
++
++/* FIXME: shouldn't this be moved to arch/arm/mach-pxa/mm.c? [RS] */
++static struct map_desc csb226_io_desc[] __initdata = {
++ /* virtual physical length domain r w c b */
++// { 0xf4000000, 0x04000000, 0x00ffffff, DOMAIN_IO, 1, 1, 0, 0 }, /* HT4562B PS/2 controller */
++ { 0xf8000000, 0x08000000, 1024*1024, DOMAIN_IO, 0, 1, 0, 0 }, /* CS8900 LAN controller */
++// { 0xe0000000, 0x20000000, 0x0fffffff, DOMAIN_IO, 1, 1, 0, 0 }, /* CompactFlash */
++#if 0
++ { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
++ { 0xf1000000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO */
++ { 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr */
++ { 0xf4000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */
++#endif
++ LAST_DESC
++};
++
++static void __init csb226_map_io(void)
++{
++ pxa_map_io();
++ iotable_init(csb226_io_desc);
++
++ /* This enables the BTUART */
++ CKEN |= CKEN7_BTUART;
++ set_GPIO_mode(GPIO42_BTRXD_MD);
++ set_GPIO_mode(GPIO43_BTTXD_MD);
++ set_GPIO_mode(GPIO44_BTCTS_MD);
++ set_GPIO_mode(GPIO45_BTRTS_MD);
++
++ /* This is for the CS8900 chip select */
++ set_GPIO_mode(GPIO78_nCS_2_MD);
++
++ /* setup sleep mode values */
++ PWER = 0x00000002;
++ PFER = 0x00000000;
++ PRER = 0x00000002;
++ PGSR0 = 0x00008000;
++ PGSR1 = 0x003F0202;
++ PGSR2 = 0x0001C000;
++ PCFR |= PCFR_OPDE;
++}
++
++MACHINE_START(CSB226, "Cogent CSB226 Development Platform")
++ MAINTAINER("Robert Schwebel, Pengutronix")
++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
++ BOOT_PARAMS(0xa0000100)
++ FIXUP(fixup_csb226)
++ MAPIO(csb226_map_io)
++ INITIRQ(csb226_init_irq)
++MACHINE_END
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/dma.c
+@@ -0,0 +1,131 @@
++/*
++ * linux/arch/arm/mach-pxa/dma.c
++ *
++ * PXA DMA registration and IRQ dispatching
++ *
++ * Author: Nicolas Pitre
++ * Created: Nov 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++
++#include <asm/system.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/dma.h>
++
++
++static struct dma_channel {
++ char *name;
++ void (*irq_handler)(int, void *, struct pt_regs *);
++ void *data;
++} dma_channels[16];
++
++
++int pxa_request_dma (char *name, pxa_dma_prio prio,
++ void (*irq_handler)(int, void *, struct pt_regs *),
++ void *data)
++{
++ unsigned long flags;
++ int i, found = 0;
++
++ /* basic sanity checks */
++ if (!name || !irq_handler)
++ return -EINVAL;
++
++ local_irq_save(flags);
++
++ /* try grabbing a DMA channel with the requested priority */
++ for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) {
++ if (!dma_channels[i].name) {
++ found = 1;
++ break;
++ }
++ }
++
++ if (!found) {
++ /* requested prio group is full, try hier priorities */
++ for (i = prio-1; i >= 0; i--) {
++ if (!dma_channels[i].name) {
++ found = 1;
++ break;
++ }
++ }
++ }
++
++ if (found) {
++ DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
++ dma_channels[i].name = name;
++ dma_channels[i].irq_handler = irq_handler;
++ dma_channels[i].data = data;
++ } else {
++ printk (KERN_WARNING "No more available DMA channels for %s\n", name);
++ i = -ENODEV;
++ }
++
++ local_irq_restore(flags);
++ return i;
++}
++
++void pxa_free_dma (int dma_ch)
++{
++ unsigned long flags;
++
++ if (!dma_channels[dma_ch].name) {
++ printk (KERN_CRIT __FUNCTION__
++ ": trying to free channel %d which is already freed\n",
++ dma_ch);
++ return;
++ }
++
++ local_irq_save(flags);
++ DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
++ dma_channels[dma_ch].name = NULL;
++ local_irq_restore(flags);
++}
++
++static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++{
++ int i, dint = DINT;
++
++ for (i = 0; i < 16; i++) {
++ if (dint & (1 << i)) {
++ struct dma_channel *channel = &dma_channels[i];
++ if (channel->name && channel->irq_handler) {
++ channel->irq_handler(i, channel->data, regs);
++ } else {
++ /*
++ * IRQ for an unregistered DMA channel:
++ * let's clear the interrupts and disable it.
++ */
++ printk (KERN_WARNING "spurious IRQ for DMA channel %d\n", i);
++ DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
++ }
++ }
++ }
++}
++
++static int __init pxa_dma_init (void)
++{
++ int ret;
++
++ ret = request_irq (IRQ_DMA, dma_irq_handler, 0, "DMA", NULL);
++ if (ret)
++ printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n");
++ return ret;
++}
++
++__initcall(pxa_dma_init);
++
++EXPORT_SYMBOL(pxa_request_dma);
++EXPORT_SYMBOL(pxa_free_dma);
++
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/generic.c
+@@ -0,0 +1,142 @@
++/*
++ * linux/arch/arm/mach-pxa/generic.c
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * Code common to all PXA machines.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Since this file should be linked before any other machine specific file,
++ * the __initcall() here will be executed first. This serves as default
++ * initialization stuff for PXA machines which can be overriden later if
++ * need be.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++
++#include <asm/hardware.h>
++#include <asm/system.h>
++#include <asm/pgtable.h>
++#include <asm/mach/map.h>
++
++#include "generic.h"
++
++/*
++ * Various clock factors driven by the CCCR register.
++ */
++
++/* Crystal Frequency to Memory Frequency Multiplier (L) */
++static unsigned char L_clk_mult[32] = { 0, 27, 32, 36, 40, 45, 0, };
++
++/* Memory Frequency to Run Mode Frequency Multiplier (M) */
++static unsigned char M_clk_mult[4] = { 0, 1, 2, 4 };
++
++/* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */
++/* Note: we store the value N * 2 here. */
++static unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 };
++
++/* Crystal clock */
++#define BASE_CLK 3686400
++
++/*
++ * Get the clock frequency as reflected by CCCR and the turbo flag.
++ * We assume these values have been applied via a fcs.
++ * If info is not 0 we also display the current settings.
++ */
++unsigned int get_clk_frequency_khz( int info)
++{
++ unsigned long cccr, turbo;
++ unsigned int l, L, m, M, n2, N;
++
++ cccr = CCCR;
++ asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (turbo) );
++
++ l = L_clk_mult[(cccr >> 0) & 0x1f];
++ m = M_clk_mult[(cccr >> 5) & 0x03];
++ n2 = N2_clk_mult[(cccr >> 7) & 0x07];
++
++ L = l * BASE_CLK;
++ M = m * L;
++ N = n2 * M / 2;
++
++ if( info)
++ {
++ L += 5000;
++ printk( KERN_INFO "Memory clock: %d.%02dMHz (*%d)\n",
++ L / 1000000, (L % 1000000) / 10000, l );
++ M += 5000;
++ printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n",
++ M / 1000000, (M % 1000000) / 10000, m );
++ N += 5000;
++ printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n",
++ N / 1000000, (N % 1000000) / 10000, n2 / 2, (n2 % 2) * 5,
++ (turbo & 1) ? "" : "in" );
++ }
++
++ return (turbo & 1) ? (N/1000) : (M/1000);
++}
++
++EXPORT_SYMBOL(get_clk_frequency_khz);
++
++/*
++ * Return the current lclk requency in units of 10kHz
++ */
++unsigned int get_lclk_frequency_10khz(void)
++{
++ return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000;
++}
++
++EXPORT_SYMBOL(get_lclk_frequency_10khz);
++
++/*
++ * Handy function to set GPIO alternate functions
++ */
++
++void set_GPIO_mode(int gpio_mode)
++{
++ long flags;
++ int gpio = gpio_mode & GPIO_MD_MASK_NR;
++ int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
++ int gafr;
++
++ local_irq_save(flags);
++ if (gpio_mode & GPIO_MD_MASK_DIR)
++ GPDR(gpio) |= GPIO_bit(gpio);
++ else
++ GPDR(gpio) &= ~GPIO_bit(gpio);
++ gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
++ GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2));
++ local_irq_restore(flags);
++}
++
++EXPORT_SYMBOL(set_GPIO_mode);
++
++/*
++ * Note that 0xfffe0000-0xffffffff is reserved for the vector table and
++ * cache flush area.
++ */
++static struct map_desc standard_io_desc[] __initdata = {
++ /* virtual physical length domain r w c b */
++ { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */
++ { 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */
++ { 0xf8000000, 0x40000000, 0x01800000, DOMAIN_IO, 0, 1, 0, 0 }, /* Devs */
++ { 0xfa000000, 0x44000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD */
++ { 0xfc000000, 0x48000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Mem Ctl */
++ { 0xff000000, 0x00000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* UNCACHED_PHYS_0 */
++ LAST_DESC
++};
++
++void __init pxa_map_io(void)
++{
++ iotable_init(standard_io_desc);
++ get_clk_frequency_khz( 1);
++}
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/generic.h
+@@ -0,0 +1,19 @@
++/*
++ * linux/arch/arm/mach-pxa/generic.h
++ *
++ * Author: Nicolas Pitre
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++extern void __init pxa_map_io(void);
++extern void __init pxa_init_irq(void);
++
++#define SET_BANK(__nr,__start,__size) \
++ mi->bank[__nr].start = (__start), \
++ mi->bank[__nr].size = (__size), \
++ mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27)
++
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/idp.c
+@@ -0,0 +1,142 @@
++/*
++ * linux/arch/arm/mach-pxa/idp.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Copyright (c) 2001 Cliff Brake, Accelent Systems Inc.
++ *
++ * 2001-09-13: Cliff Brake <cbrake@accelent.com>
++ * Initial code
++ */
++#include <linux/init.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/arch/irq.h>
++
++#include "generic.h"
++
++#define PXA_IDP_REV02
++
++#ifndef PXA_IDP_REV02
++/* shadow registers for write only registers */
++unsigned int idp_cpld_led_control_shadow = 0x1;
++unsigned int idp_cpld_periph_pwr_shadow = 0xd;
++unsigned int ipd_cpld_cir_shadow = 0;
++unsigned int idp_cpld_kb_col_high_shadow = 0;
++unsigned int idp_cpld_kb_col_low_shadow = 0;
++unsigned int idp_cpld_pccard_en_shadow = 0xC3;
++unsigned int idp_cpld_gpioh_dir_shadow = 0;
++unsigned int idp_cpld_gpioh_value_shadow = 0;
++unsigned int idp_cpld_gpiol_dir_shadow = 0;
++unsigned int idp_cpld_gpiol_value_shadow = 0;
++
++/*
++ * enable all LCD signals -- they should still be on
++ * write protect flash
++ * enable all serial port transceivers
++ */
++
++unsigned int idp_control_port_shadow = ((0x7 << 21) | /* LCD power */
++ (0x1 << 19) | /* disable flash write enable */
++ (0x7 << 9)); /* enable serial port transeivers */
++
++#endif
++
++static int __init idp_init(void)
++{
++ printk("idp_init()\n");
++ return 0;
++}
++
++__initcall(idp_init);
++
++static void __init idp_init_irq(void)
++{
++ pxa_init_irq();
++}
++
++static void __init
++fixup_idp(struct machine_desc *desc, struct param_struct *params,
++ char **cmdline, struct meminfo *mi)
++{
++#ifdef PXA_IDP_REV02
++ SET_BANK (0, 0xa0000000, 64*1024*1024);
++#else
++ SET_BANK (0, 0xa0000000, 32*1024*1024);
++#endif
++ mi->nr_banks = 1;
++#if 0
++ setup_ramdisk (1, 0, 0, 8192);
++ setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024);
++ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
++#endif
++}
++
++static struct map_desc idp_io_desc[] __initdata = {
++ /* virtual physical length domain r w c b */
++
++
++#ifndef PXA_IDP_REV02
++ { IDP_CTRL_PORT_BASE,
++ IDP_CTRL_PORT_PHYS,
++ IDP_CTRL_PORT_SIZE,
++ DOMAIN_IO,
++ 0, 1, 0, 0 },
++#endif
++
++ { IDP_IDE_BASE,
++ IDP_IDE_PHYS,
++ IDP_IDE_SIZE,
++ DOMAIN_IO,
++ 0, 1, 0, 0 },
++ { IDP_ETH_BASE,
++ IDP_ETH_PHYS,
++ IDP_ETH_SIZE,
++ DOMAIN_IO,
++ 0, 1, 0, 0 },
++ { IDP_COREVOLT_BASE,
++ IDP_COREVOLT_PHYS,
++ IDP_COREVOLT_SIZE,
++ DOMAIN_IO,
++ 0, 1, 0, 0 },
++ { IDP_CPLD_BASE,
++ IDP_CPLD_PHYS,
++ IDP_CPLD_SIZE,
++ DOMAIN_IO,
++ 0, 1, 0, 0 },
++
++ LAST_DESC
++};
++
++static void __init idp_map_io(void)
++{
++ pxa_map_io();
++ iotable_init(idp_io_desc);
++
++ set_GPIO_IRQ_edge(IRQ_TO_GPIO(TOUCH_PANEL_IRQ), TOUCH_PANEL_IRQ_EDGE);
++ set_GPIO_IRQ_edge(IRQ_TO_GPIO(SMC_IRQ), GPIO_RISING_EDGE);
++}
++
++MACHINE_START(PXA_IDP, "Accelent Xscale IDP")
++ MAINTAINER("Accelent Systems Inc.")
++ BOOT_MEM(0xa0000000, 0x40000000, 0xfc000000)
++ FIXUP(fixup_idp)
++ MAPIO(idp_map_io)
++ INITIRQ(idp_init_irq)
++MACHINE_END
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/innokom.c
+@@ -0,0 +1,129 @@
++/*
++ * linux/arch/arm/mach-pxa/innokom.c
++ *
++ * (c) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/init.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/arch/irq.h>
++#include <asm/arch/irqs.h>
++#include <asm/hardware/sa1111.h>
++
++#include "generic.h"
++
++
++static void __init innokom_init_irq(void)
++{
++ pxa_init_irq();
++}
++
++
++void sw_update_handler( int irq, void* dev_id,struct pt_regs* regs)
++{
++}
++
++
++void reset_handler( int irq, void* dev_id,struct pt_regs* regs)
++{
++}
++
++
++static int __init innokom_init(void)
++{
++ int sw_irq = GPIO_2_80_TO_IRQ(11); /* software update button */
++ int reset_irq = GPIO_2_80_TO_IRQ(3); /* reset button */
++
++ set_GPIO_IRQ_edge(11,GPIO_FALLING_EDGE);
++ if (request_irq(sw_irq,sw_update_handler,SA_INTERRUPT,"software update button",NULL))
++ printk(KERN_INFO "innokom: can't get assigned irq %i\n",sw_irq);
++
++ set_GPIO_IRQ_edge(3,GPIO_FALLING_EDGE);
++ if (request_irq(reset_irq,reset_handler,SA_INTERRUPT,"reset button",NULL))
++ printk(KERN_INFO "innokom: can't get assigned irq %i\n",reset_irq);
++
++ return 0;
++}
++
++
++__initcall(innokom_init);
++
++
++static void __init
++fixup_innokom(struct machine_desc *desc, struct param_struct *params,
++ char **cmdline, struct meminfo *mi)
++{
++ /* we probably want to get this information from the bootloader later */
++ SET_BANK (0, 0xa0000000, 64*1024*1024);
++ mi->nr_banks = 1;
++}
++
++
++/* memory mapping */
++static struct map_desc innokom_io_desc[] __initdata = {
++/* virtual physical length domain r w c b */
++ { INNOKOM_ETH_BASE, INNOKOM_ETH_PHYS, INNOKOM_ETH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* ETH SMSC 91111 */
++ LAST_DESC
++};
++
++static void __init innokom_map_io(void)
++{
++ pxa_map_io();
++ iotable_init(innokom_io_desc);
++
++ /* Enable the BTUART */
++ CKEN |= CKEN7_BTUART;
++ set_GPIO_mode(GPIO42_BTRXD_MD);
++ set_GPIO_mode(GPIO43_BTTXD_MD);
++ set_GPIO_mode(GPIO44_BTCTS_MD);
++ set_GPIO_mode(GPIO45_BTRTS_MD);
++
++ set_GPIO_mode(GPIO33_nCS_5_MD); /* SMSC network chip */
++
++ /* setup sleep mode values */
++ PWER = 0x00000002;
++ PFER = 0x00000000;
++ PRER = 0x00000002;
++ PGSR0 = 0x00008000;
++ PGSR1 = 0x003F0202;
++ PGSR2 = 0x0001C000;
++ PCFR |= PCFR_OPDE;
++}
++
++MACHINE_START(INNOKOM, "Auerswald Innokom")
++ MAINTAINER("Robert Schwebel, Pengutronix")
++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
++ BOOT_PARAMS(0xa0000100)
++ FIXUP(fixup_innokom)
++ MAPIO(innokom_map_io)
++ INITIRQ(innokom_init_irq)
++MACHINE_END
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/irq.c
+@@ -0,0 +1,282 @@
++/*
++ * linux/arch/arm/mach-pxa/irq.c
++ *
++ * Generic PXA IRQ handling, GPIO IRQ demultiplexing, etc.
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/mach/irq.h>
++#include <asm/arch/irq.h>
++
++#include "generic.h"
++
++
++/*
++ * PXA GPIO edge detection for IRQs:
++ * IRQs are generated on Falling-Edge, Rising-Edge, or both.
++ * This must be called *before* the appropriate IRQ is registered.
++ * Use this instead of directly setting GRER/GFER.
++ */
++
++static int GPIO_IRQ_rising_edge[3];
++static int GPIO_IRQ_falling_edge[3];
++
++void set_GPIO_IRQ_edge (int gpio_nr, int edge)
++{
++ long flags;
++ local_irq_save(flags);
++ set_GPIO_mode(gpio_nr | GPIO_IN);
++ if (edge & GPIO_FALLING_EDGE)
++ set_bit (gpio_nr, GPIO_IRQ_falling_edge);
++ else
++ clear_bit (gpio_nr, GPIO_IRQ_falling_edge);
++ if (edge & GPIO_RISING_EDGE)
++ set_bit (gpio_nr, GPIO_IRQ_rising_edge);
++ else
++ clear_bit (gpio_nr, GPIO_IRQ_rising_edge);
++ irq_desc[IRQ_GPIO(gpio_nr)].valid = 1;
++ local_irq_restore(flags);
++}
++
++EXPORT_SYMBOL(set_GPIO_IRQ_edge);
++
++
++/*
++ * We don't need to ACK IRQs on the PXA unless they're GPIOs
++ * this is for IRQs known as PXA_IRQ([10...31]).
++ */
++
++static void pxa_mask_irq(unsigned int irq)
++{
++ ICMR &= ~(1 << (irq + PXA_IRQ_SKIP));
++}
++
++static void pxa_unmask_irq(unsigned int irq)
++{
++ ICMR |= (1 << (irq + PXA_IRQ_SKIP));
++}
++
++/*
++ * GPIO IRQs must be acknoledged. This is for GPIO 0 and 1.
++ */
++
++static void pxa_mask_and_ack_GPIO_0_1_irq(unsigned int irq)
++{
++ ICMR &= ~(1 << (irq + PXA_IRQ_SKIP));
++ GEDR0 = (1 << (irq - IRQ_GPIO0));
++}
++
++static void pxa_mask_GPIO_0_1_irq(unsigned int irq)
++{
++ ICMR &= ~(1 << (irq + PXA_IRQ_SKIP));
++}
++
++static void pxa_unmask_GPIO_0_1_irq(unsigned int irq)
++{
++ int gpio = irq - IRQ_GPIO0;
++ GRER0 = (GRER0 & ~(1 << gpio))|(GPIO_IRQ_rising_edge[0] & (1 << gpio));
++ GFER0 = (GFER0 & ~(1 << gpio))|(GPIO_IRQ_falling_edge[0] & (1 << gpio));
++ ICMR |= (1 << (irq + PXA_IRQ_SKIP));
++}
++
++/*
++ * Demux handler for GPIO 2-80 edge detect interrupts
++ */
++
++static int GPIO_2_80_enabled[3]; /* enabled i.e. unmasked GPIO IRQs */
++static int GPIO_2_80_spurious[3]; /* GPIOs that triggered when masked */
++
++static void pxa_GPIO_2_80_demux(int irq, void *dev_id,
++ struct pt_regs *regs)
++{
++ int i, gedr, spurious;
++
++ while ((gedr = (GEDR0 & ~3))) {
++ /*
++ * We don't want to clear GRER/GFER when the corresponding
++ * IRQ is masked because we could miss a level transition
++ * i.e. an IRQ which need servicing as soon as it is
++ * unmasked. However, such situation should happen only
++ * during the loop below. Thus all IRQs which aren't
++ * enabled at this point are considered spurious. Those
++ * are cleared but only de-activated if they happen twice.
++ */
++ spurious = gedr & ~GPIO_2_80_enabled[0];
++ if (spurious) {
++ GEDR0 = spurious;
++ GRER0 &= ~(spurious & GPIO_2_80_spurious[0]);
++ GFER0 &= ~(spurious & GPIO_2_80_spurious[0]);
++ GPIO_2_80_spurious[0] |= spurious;
++ gedr ^= spurious;
++ if (!gedr) continue;
++ }
++
++ for (i = 2; i < 32; ++i) {
++ if (gedr & (1<<i)) {
++ do_IRQ (IRQ_GPIO(2) + i - 2, regs);
++ }
++ }
++ }
++ while ((gedr = GEDR1)) {
++ spurious = gedr & ~GPIO_2_80_enabled[1];
++ if (spurious) {
++ GEDR1 = spurious;
++ GRER1 &= ~(spurious & GPIO_2_80_spurious[1]);
++ GFER1 &= ~(spurious & GPIO_2_80_spurious[1]);
++ GPIO_2_80_spurious[1] |= spurious;
++ gedr ^= spurious;
++ if (!gedr) continue;
++ }
++
++ for (i = 0; i < 32; ++i) {
++ if (gedr & (1<<i)) {
++ do_IRQ (IRQ_GPIO(32) + i, regs);
++ }
++ }
++ }
++ while ((gedr = (GEDR2 & 0x0001ffff))) {
++ spurious = gedr & ~GPIO_2_80_enabled[2];
++ if (spurious) {
++ GEDR2 = spurious;
++ GRER2 &= ~(spurious & GPIO_2_80_spurious[2]);
++ GFER2 &= ~(spurious & GPIO_2_80_spurious[2]);
++ GPIO_2_80_spurious[2] |= spurious;
++ gedr ^= spurious;
++ if (!gedr) continue;
++ }
++
++ for (i = 0; i < 17; ++i) {
++ if (gedr & (1<<i)) {
++ do_IRQ (IRQ_GPIO(64) + i, regs);
++ }
++ }
++ }
++}
++
++static struct irqaction GPIO_2_80_irqaction = {
++ name: "GPIO 2-80",
++ handler: pxa_GPIO_2_80_demux,
++ flags: SA_INTERRUPT
++};
++
++#define GRER_x(i) (*(&GRER0 + (i)))
++#define GFER_x(i) (*(&GFER0 + (i)))
++#define GEDR_x(i) (*(&GEDR0 + (i)))
++#define GPLR_x(i) (*(&GPLR0 + (i)))
++
++static void pxa_mask_and_ack_GPIO_2_80_irq(unsigned int irq)
++{
++ int gpio_nr = IRQ_TO_GPIO_2_80(irq);
++ int mask = 1 << (gpio_nr & 0x1f);
++ int index = gpio_nr >> 5;
++ GPIO_2_80_spurious[index] &= ~mask;
++ GPIO_2_80_enabled[index] &= ~mask;
++ GEDR_x(index) = mask;
++}
++
++static void pxa_mask_GPIO_2_80_irq(unsigned int irq)
++{
++ int gpio_nr = IRQ_TO_GPIO_2_80(irq);
++ int mask = 1 << (gpio_nr & 0x1f);
++ int index = gpio_nr >> 5;
++ GPIO_2_80_spurious[index] &= ~mask;
++ GPIO_2_80_enabled[index] &= ~mask;
++}
++
++static void pxa_unmask_GPIO_2_80_irq(unsigned int irq)
++{
++ int gpio_nr = IRQ_TO_GPIO_2_80(irq);
++ int mask = 1 << (gpio_nr & 0x1f);
++ int index = gpio_nr >> 5;
++ if (GPIO_2_80_spurious[index] & mask) {
++ /*
++ * We don't want to miss an interrupt that would have occurred
++ * while it was masked. Simulate it if it is the case.
++ */
++ int state = GPLR_x(index);
++ if (((state & GPIO_IRQ_rising_edge[index]) |
++ (~state & GPIO_IRQ_falling_edge[index])) & mask)
++ {
++ /* just in case it gets referenced: */
++ struct pt_regs dummy;
++
++ memzero(&dummy, sizeof(dummy));
++ do_IRQ(irq, &dummy);
++
++ /* we are being called recursively from do_IRQ() */
++ return;
++ }
++ }
++ GPIO_2_80_enabled[index] |= mask;
++ GRER_x(index) =
++ (GRER_x(index) & ~mask) | (GPIO_IRQ_rising_edge[index] & mask);
++ GFER_x(index) =
++ (GFER_x(index) & ~mask) | (GPIO_IRQ_falling_edge[index] & mask);
++}
++
++
++void __init pxa_init_irq(void)
++{
++ int irq;
++
++ /* disable all IRQs */
++ ICMR = 0;
++
++ /* all IRQs are IRQ, not FIQ */
++ ICLR = 0;
++
++ /* clear all GPIO edge detects */
++ GFER0 = GFER1 = GFER2 = 0;
++ GRER0 = GRER1 = GRER2 = 0;
++ GEDR0 = GEDR0;
++ GEDR1 = GEDR1;
++ GEDR2 = GEDR2;
++
++ /* only unmasked interrupts kick us out of idle */
++ ICCR = 1;
++
++ for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) {
++ irq_desc[irq].valid = 1;
++ irq_desc[irq].probe_ok = 0;
++ irq_desc[irq].mask_ack = pxa_mask_irq;
++ irq_desc[irq].mask = pxa_mask_irq;
++ irq_desc[irq].unmask = pxa_unmask_irq;
++ }
++
++ /*
++ * Note: GPIO IRQs are initially invalid until set_GPIO_IRQ_edge()
++ * is called at least once.
++ */
++
++ for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
++ irq_desc[irq].valid = 0;
++ irq_desc[irq].probe_ok = 1;
++ irq_desc[irq].mask_ack = pxa_mask_and_ack_GPIO_0_1_irq;
++ irq_desc[irq].mask = pxa_mask_GPIO_0_1_irq;
++ irq_desc[irq].unmask = pxa_unmask_GPIO_0_1_irq;
++ }
++
++ for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(80); irq++) {
++ irq_desc[irq].valid = 0;
++ irq_desc[irq].probe_ok = 1;
++ irq_desc[irq].mask_ack = pxa_mask_and_ack_GPIO_2_80_irq;
++ irq_desc[irq].mask = pxa_mask_GPIO_2_80_irq;
++ irq_desc[irq].unmask = pxa_unmask_GPIO_2_80_irq;
++ }
++ setup_arm_irq( IRQ_GPIO_2_80, &GPIO_2_80_irqaction );
++}
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/leds-cerf.c
+@@ -0,0 +1,135 @@
++/*
++ * linux/arch/arm/mach-pxa/leds-cerf.c
++ *
++ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
++ *
++ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
++ *
++ * Original (leds-footbridge.c) by Russell King
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++
++#include <linux/config.h>
++#include <linux/init.h>
++
++#include <asm/hardware.h>
++#include <asm/leds.h>
++#include <asm/system.h>
++
++#include "leds.h"
++
++
++#define LED_STATE_ENABLED 1
++#define LED_STATE_CLAIMED 2
++
++static unsigned int led_state;
++static unsigned int hw_led_state;
++
++void pxa_cerf_leds_event(led_event_t evt)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ switch (evt) {
++ case led_start:
++ hw_led_state = CERF_HEARTBEAT_LED;
++ led_state = LED_STATE_ENABLED;
++ break;
++
++ case led_stop:
++ led_state &= ~LED_STATE_ENABLED;
++ break;
++
++ case led_claim:
++ led_state |= LED_STATE_CLAIMED;
++ hw_led_state = CERF_HEARTBEAT_LED;
++ break;
++
++ case led_release:
++ led_state &= ~LED_STATE_CLAIMED;
++ hw_led_state = CERF_HEARTBEAT_LED;
++ break;
++
++#ifdef CONFIG_LEDS_TIMER
++ case led_timer:
++ if (!(led_state & LED_STATE_CLAIMED))
++ hw_led_state ^= CERF_HEARTBEAT_LED;
++ break;
++#endif
++
++#ifdef CONFIG_LEDS_CPU
++ case led_idle_start:
++ if (!(led_state & LED_STATE_CLAIMED))
++ hw_led_state |= CERF_SYS_BUSY_LED;
++ break;
++
++ case led_idle_end:
++ if (!(led_state & LED_STATE_CLAIMED))
++ hw_led_state &= ~CERF_SYS_BUSY_LED;
++ break;
++#endif
++
++ case led_halted:
++ break;
++
++ case led_green_on:
++ if (led_state & LED_STATE_CLAIMED)
++ hw_led_state &= ~CERF_HEARTBEAT_LED;
++ break;
++
++ case led_green_off:
++ if (led_state & LED_STATE_CLAIMED)
++ hw_led_state |= CERF_HEARTBEAT_LED;
++ break;
++
++ case led_amber_on:
++ break;
++
++ case led_amber_off:
++ break;
++
++#ifndef CONFIG_PXA_CERF_PDA
++ case led_red_on:
++ if (led_state & LED_STATE_CLAIMED)
++ hw_led_state &= ~CERF_SYS_BUSY_LED;
++ break;
++
++ case led_red_off:
++ if (led_state & LED_STATE_CLAIMED)
++ hw_led_state |= CERF_SYS_BUSY_LED;
++ break;
++#endif
++ default:
++ break;
++ }
++
++ if (led_state & LED_STATE_ENABLED)
++ {
++ switch (hw_led_state) {
++ case 0: // all on
++ CERF_HEARTBEAT_LED_ON;
++ CERF_SYS_BUSY_LED_ON;
++ break;
++ case 1: // turn off heartbeat, status on:
++ CERF_HEARTBEAT_LED_OFF;
++ CERF_SYS_BUSY_LED_ON;
++ break;
++ case 2: // status off, heartbeat on:
++ CERF_HEARTBEAT_LED_ON;
++ CERF_SYS_BUSY_LED_OFF;
++ break;
++ case 3: // turn them both off...
++ CERF_HEARTBEAT_LED_OFF;
++ CERF_SYS_BUSY_LED_OFF;
++ break;
++ default:
++ break;
++ }
++ }
++ local_irq_restore(flags);
++}
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/leds-idp.c
+@@ -0,0 +1,112 @@
++/*
++ * linux/arch/arm/mach-pxa/leds-idp.c
++ *
++ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
++ *
++ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
++ *
++ * Original (leds-footbridge.c) by Russell King
++ *
++ * Macros for actual LED manipulation should be in machine specific
++ * files in this 'mach' directory.
++ */
++
++
++#include <linux/config.h>
++#include <linux/init.h>
++
++#include <asm/hardware.h>
++#include <asm/leds.h>
++#include <asm/system.h>
++
++#include "leds.h"
++
++#define LED_STATE_ENABLED 1
++#define LED_STATE_CLAIMED 2
++
++static unsigned int led_state;
++static unsigned int hw_led_state;
++
++void idp_leds_event(led_event_t evt)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ switch (evt) {
++ case led_start:
++ hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
++ led_state = LED_STATE_ENABLED;
++ break;
++
++ case led_stop:
++ led_state &= ~LED_STATE_ENABLED;
++ break;
++
++ case led_claim:
++ led_state |= LED_STATE_CLAIMED;
++ hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
++ break;
++
++ case led_release:
++ led_state &= ~LED_STATE_CLAIMED;
++ hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
++ break;
++
++#ifdef CONFIG_LEDS_TIMER
++ case led_timer:
++ if (!(led_state & LED_STATE_CLAIMED))
++ hw_led_state ^= IDP_HB_LED;
++ break;
++#endif
++
++#ifdef CONFIG_LEDS_CPU
++ case led_idle_start:
++ if (!(led_state & LED_STATE_CLAIMED))
++ hw_led_state |= IDP_BUSY_LED;
++ break;
++
++ case led_idle_end:
++ if (!(led_state & LED_STATE_CLAIMED))
++ hw_led_state &= ~IDP_BUSY_LED;
++ break;
++#endif
++
++ case led_halted:
++ break;
++
++ case led_green_on:
++ if (led_state & LED_STATE_CLAIMED)
++ hw_led_state &= ~IDP_HB_LED;
++ break;
++
++ case led_green_off:
++ if (led_state & LED_STATE_CLAIMED)
++ hw_led_state |= IDP_HB_LED;
++ break;
++
++ case led_amber_on:
++ break;
++
++ case led_amber_off:
++ break;
++
++ case led_red_on:
++ if (led_state & LED_STATE_CLAIMED)
++ hw_led_state &= ~IDP_BUSY_LED;
++ break;
++
++ case led_red_off:
++ if (led_state & LED_STATE_CLAIMED)
++ hw_led_state |= IDP_BUSY_LED;
++ break;
++
++ default:
++ break;
++ }
++
++ if (led_state & LED_STATE_ENABLED)
++ IDP_WRITE_LEDS(hw_led_state);
++
++ local_irq_restore(flags);
++}
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/leds-lubbock.c
+@@ -0,0 +1,134 @@
++/*
++ * linux/arch/arm/mach-pxa/leds-lubbock.c
++ *
++ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
++ *
++ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
++ *
++ * Original (leds-footbridge.c) by Russell King
++ *
++ * See leds.h for bit definitions. The first version defines D28 on the
++ * Lubbock dev board as the heartbeat, and D27 as the Sys_busy led.
++ * There's plenty more if you're interested in adding them :)
++ */
++
++
++#include <linux/config.h>
++#include <linux/init.h>
++
++#include <asm/hardware.h>
++#include <asm/leds.h>
++#include <asm/system.h>
++
++#include "leds.h"
++
++
++#define LED_STATE_ENABLED 1
++#define LED_STATE_CLAIMED 2
++
++static unsigned int led_state;
++static unsigned int hw_led_state;
++
++void lubbock_leds_event(led_event_t evt)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ switch (evt) {
++ case led_start:
++ hw_led_state = HEARTBEAT_LED | SYS_BUSY_LED;
++ led_state = LED_STATE_ENABLED;
++ break;
++
++ case led_stop:
++ led_state &= ~LED_STATE_ENABLED;
++ break;
++
++ case led_claim:
++ led_state |= LED_STATE_CLAIMED;
++ hw_led_state = HEARTBEAT_LED | SYS_BUSY_LED;
++ break;
++
++ case led_release:
++ led_state &= ~LED_STATE_CLAIMED;
++ hw_led_state = HEARTBEAT_LED | SYS_BUSY_LED;
++ break;
++
++#ifdef CONFIG_LEDS_TIMER
++ case led_timer:
++ if (!(led_state & LED_STATE_CLAIMED))
++ hw_led_state ^= HEARTBEAT_LED;
++ break;
++#endif
++
++#ifdef CONFIG_LEDS_CPU
++ case led_idle_start:
++ if (!(led_state & LED_STATE_CLAIMED))
++ hw_led_state |= SYS_BUSY_LED;
++ break;
++
++ case led_idle_end:
++ if (!(led_state & LED_STATE_CLAIMED))
++ hw_led_state &= ~SYS_BUSY_LED;
++ break;
++#endif
++
++ case led_halted:
++ break;
++
++ case led_green_on:
++ if (led_state & LED_STATE_CLAIMED)
++ hw_led_state &= ~HEARTBEAT_LED;
++ break;
++
++ case led_green_off:
++ if (led_state & LED_STATE_CLAIMED)
++ hw_led_state |= HEARTBEAT_LED;
++ break;
++
++ case led_amber_on:
++ break;
++
++ case led_amber_off:
++ break;
++
++ case led_red_on:
++ if (led_state & LED_STATE_CLAIMED)
++ hw_led_state &= ~SYS_BUSY_LED;
++ break;
++
++ case led_red_off:
++ if (led_state & LED_STATE_CLAIMED)
++ hw_led_state |= SYS_BUSY_LED;
++ break;
++
++ default:
++ break;
++ }
++
++ if (led_state & LED_STATE_ENABLED)
++ {
++ switch (hw_led_state) {
++ case 0: // all on
++ HEARTBEAT_LED_ON;
++ SYS_BUSY_LED_ON;
++ break;
++ case 1: // turn off heartbeat, status on:
++ HEARTBEAT_LED_OFF;
++ SYS_BUSY_LED_ON;
++ break;
++ case 2: // status off, heartbeat on:
++ HEARTBEAT_LED_ON;
++ SYS_BUSY_LED_OFF;
++ break;
++ case 3: // turn them both off...
++ HEARTBEAT_LED_OFF;
++ SYS_BUSY_LED_OFF;
++ break;
++ default:
++ break;
++ }
++ }
++ local_irq_restore(flags);
++}
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/leds.c
+@@ -0,0 +1,32 @@
++/*
++ * linux/arch/arm/mach-pxa/leds.c
++ *
++ * xscale LEDs dispatcher
++ *
++ * Copyright (C) 2001 Nicolas Pitre
++ *
++ * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
++ */
++#include <linux/config.h>
++#include <linux/init.h>
++
++#include <asm/leds.h>
++#include <asm/mach-types.h>
++
++#include "leds.h"
++
++static int __init
++pxa_leds_init(void)
++{
++ if (machine_is_lubbock())
++ leds_event = lubbock_leds_event;
++ if (machine_is_pxa_idp())
++ leds_event = idp_leds_event;
++ if (machine_is_pxa_cerf())
++ leds_event = pxa_cerf_leds_event;
++
++ leds_event(led_start);
++ return 0;
++}
++
++__initcall(pxa_leds_init);
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/leds.h
+@@ -0,0 +1,12 @@
++/*
++ * include/asm-arm/arch-pxa/leds.h
++ *
++ * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
++ *
++ * blinky lights for various PXA-based systems:
++ *
++ */
++
++extern void lubbock_leds_event(led_event_t evt);
++extern void idp_leds_event(led_event_t evt);
++extern void pxa_cerf_leds_event(led_event_t evt);
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/lubbock.c
+@@ -0,0 +1,157 @@
++/*
++ * linux/arch/arm/mach-pxa/lubbock.c
++ *
++ * Support for the Intel DBPXA250 Development Platform.
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/init.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/bitops.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/arch/irq.h>
++#include <asm/hardware/sa1111.h>
++
++#include "generic.h"
++
++#ifdef CONFIG_SA1111
++ #include "sa1111.h"
++#endif
++
++
++static unsigned long lubbock_irq_enabled;
++
++static void lubbock_mask_irq(unsigned int irq)
++{
++ int lubbock_irq = (irq - LUBBOCK_IRQ(0));
++ LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq));
++}
++
++static void lubbock_unmask_irq(unsigned int irq)
++{
++ int lubbock_irq = (irq - LUBBOCK_IRQ(0));
++ /* the irq can be acknowledged only if deasserted, so it's done here */
++ LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq);
++ LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq));
++}
++
++void lubbock_irq_demux(int irq, void *dev_id, struct pt_regs *regs)
++{
++ unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
++ do {
++ GEDR(0) = GPIO_bit(0); /* clear useless edge notification */
++ if (likely(pending))
++ do_IRQ( LUBBOCK_IRQ(0) + __ffs(pending), regs );
++ pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
++ } while (pending);
++}
++
++static struct irqaction lubbock_irq = {
++ name: "Lubbock FPGA",
++ handler: lubbock_irq_demux,
++ flags: SA_INTERRUPT
++};
++
++static void __init lubbock_init_irq(void)
++{
++ int irq;
++
++ pxa_init_irq();
++
++ /* setup extra lubbock irqs */
++ for(irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) {
++ irq_desc[irq].valid = 1;
++ irq_desc[irq].probe_ok = 1;
++ irq_desc[irq].mask_ack = lubbock_mask_irq;
++ irq_desc[irq].mask = lubbock_mask_irq;
++ irq_desc[irq].unmask = lubbock_unmask_irq;
++ }
++
++ set_GPIO_IRQ_edge(GPIO_LUBBOCK_IRQ, GPIO_FALLING_EDGE);
++ setup_arm_irq(IRQ_GPIO_LUBBOCK_IRQ, &lubbock_irq);
++}
++
++static int __init lubbock_init(void)
++{
++ int ret;
++
++ ret = sa1111_probe(LUBBOCK_SA1111_BASE);
++ if (ret)
++ return ret;
++ sa1111_wake();
++ sa1111_init_irq(LUBBOCK_SA1111_IRQ);
++ return 0;
++}
++
++__initcall(lubbock_init);
++
++static void __init
++fixup_lubbock(struct machine_desc *desc, struct param_struct *params,
++ char **cmdline, struct meminfo *mi)
++{
++ /* Some boards have 32MB some 64MB. Let's use a safe default */
++ SET_BANK (0, 0xa0000000, 32*1024*1024);
++ mi->nr_banks = 1;
++}
++
++static struct map_desc lubbock_io_desc[] __initdata = {
++ /* virtual physical length domain r w c b */
++ { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
++ { 0xf1000000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO */
++ { 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr */
++ { 0xf4000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */
++ LAST_DESC
++};
++
++static void __init lubbock_map_io(void)
++{
++ pxa_map_io();
++ iotable_init(lubbock_io_desc);
++
++ /* This enables the BTUART */
++ CKEN |= CKEN7_BTUART;
++ set_GPIO_mode(GPIO42_BTRXD_MD);
++ set_GPIO_mode(GPIO43_BTTXD_MD);
++ set_GPIO_mode(GPIO44_BTCTS_MD);
++ set_GPIO_mode(GPIO45_BTRTS_MD);
++
++ /* This is for the SMC chip select */
++ set_GPIO_mode(GPIO79_nCS_3_MD);
++
++ /* setup sleep mode values */
++ PWER = 0x00000002;
++ PFER = 0x00000000;
++ PRER = 0x00000002;
++ PGSR0 = 0x00008000;
++ PGSR1 = 0x003F0202;
++ PGSR2 = 0x0001C000;
++ PCFR |= PCFR_OPDE;
++}
++
++MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform")
++ MAINTAINER("MontaVista Software Inc.")
++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
++ FIXUP(fixup_lubbock)
++ MAPIO(lubbock_map_io)
++ INITIRQ(lubbock_init_irq)
++MACHINE_END
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/pm.c
+@@ -0,0 +1,265 @@
++/*
++ * PXA250/210 Power Management Routines
++ *
++ * Original code for the SA11x0:
++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
++ *
++ * Modified for the PXA250 by Nicolas Pitre:
++ * Copyright (c) 2002 Monta Vista Software, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/pm.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/sysctl.h>
++#include <linux/errno.h>
++
++#include <asm/hardware.h>
++#include <asm/memory.h>
++#include <asm/system.h>
++#include <asm/leds.h>
++
++
++/*
++ * Debug macros
++ */
++#undef DEBUG
++
++extern void pxa_cpu_suspend(void);
++extern void pxa_cpu_resume(void);
++
++#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
++#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
++
++/*
++ * List of global PXA peripheral registers to preserve.
++ * More ones like CP and general purpose register values are preserved
++ * with the stack pointer in sleep.S.
++ */
++enum { SLEEP_SAVE_START = 0,
++
++ SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
++ SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
++
++ SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2,
++ SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2,
++ SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2,
++ SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR2_L,
++ SLEEP_SAVE_GAFR0_U, SLEEP_SAVE_GAFR1_U, SLEEP_SAVE_GAFR2_U,
++
++ SLEEP_SAVE_FFIER, SLEEP_SAVE_FFLCR, SLEEP_SAVE_FFMCR,
++ SLEEP_SAVE_FFSPR, SLEEP_SAVE_FFISR,
++ SLEEP_SAVE_FFDLL, SLEEP_SAVE_FFDLH,
++
++ SLEEP_SAVE_ICMR,
++ SLEEP_SAVE_CKEN,
++
++ SLEEP_SAVE_CKSUM,
++
++ SLEEP_SAVE_SIZE
++};
++
++
++int pm_do_suspend(void)
++{
++ unsigned long sleep_save[SLEEP_SAVE_SIZE];
++ unsigned long checksum = 0;
++ int i;
++
++ cli();
++ clf();
++
++ leds_event(led_stop);
++
++ /* preserve current time */
++ RCNR = xtime.tv_sec;
++
++ /*
++ * Temporary solution. This won't be necessary once
++ * we move pxa support into the serial/* driver
++ * Save the FF UART
++ */
++ SAVE(FFIER);
++ SAVE(FFLCR);
++ SAVE(FFMCR);
++ SAVE(FFSPR);
++ SAVE(FFISR);
++ FFLCR |= 0x80;
++ SAVE(FFDLL);
++ SAVE(FFDLH);
++ FFLCR &= 0xef;
++
++ /* save vital registers */
++ SAVE(OSCR);
++ SAVE(OSMR0);
++ SAVE(OSMR1);
++ SAVE(OSMR2);
++ SAVE(OSMR3);
++ SAVE(OIER);
++
++ SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
++ SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
++ SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
++ SAVE(GAFR0_L); SAVE(GAFR0_U);
++ SAVE(GAFR1_L); SAVE(GAFR1_U);
++ SAVE(GAFR2_L); SAVE(GAFR2_U);
++
++ SAVE(ICMR);
++ ICMR = 0;
++
++ SAVE(CKEN);
++ CKEN = 0;
++
++ /* Note: wake up source are set up in each machine specific files */
++
++ /* clear GPIO transition detect bits */
++ GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2;
++
++ /* Clear sleep reset status */
++ RCSR = RCSR_SMR;
++
++ /* set resume return address */
++ PSPR = virt_to_phys(pxa_cpu_resume);
++
++ /* before sleeping, calculate and save a checksum */
++ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
++ checksum += sleep_save[i];
++ sleep_save[SLEEP_SAVE_CKSUM] = checksum;
++
++ /* *** go zzz *** */
++ pxa_cpu_suspend();
++
++ /* after sleeping, validate the checksum */
++ checksum = 0;
++ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
++ checksum += sleep_save[i];
++
++ /* if invalid, display message and wait for a hardware reset */
++ if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) {
++#ifdef CONFIG_ARCH_LUBBOCK
++ LUB_HEXLED = 0xbadbadc5;
++#endif
++ while (1);
++ }
++
++ /* ensure not to come back here if it wasn't intended */
++ PSPR = 0;
++
++ /* restore registers */
++ RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
++ RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
++ RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
++ RESTORE(GAFR0_L); RESTORE(GAFR0_U);
++ RESTORE(GAFR1_L); RESTORE(GAFR1_U);
++ RESTORE(GAFR2_L); RESTORE(GAFR2_U);
++
++ PSSR = PSSR_PH;
++
++ RESTORE(OSMR0);
++ RESTORE(OSMR1);
++ RESTORE(OSMR2);
++ RESTORE(OSMR3);
++ RESTORE(OSCR);
++ RESTORE(OIER);
++
++ RESTORE(CKEN);
++
++ ICLR = 0;
++ ICCR = 1;
++ RESTORE(ICMR);
++
++ /*
++ * Temporary solution. This won't be necessary once
++ * we move pxa support into the serial/* driver.
++ * Restore the FF UART.
++ */
++ RESTORE(FFMCR);
++ RESTORE(FFSPR);
++ RESTORE(FFLCR);
++ FFLCR |= 0x80;
++ RESTORE(FFDLH);
++ RESTORE(FFDLL);
++ RESTORE(FFLCR);
++ RESTORE(FFISR);
++ FFFCR = 0x07;
++ RESTORE(FFIER);
++
++ /* restore current time */
++ xtime.tv_sec = RCNR;
++
++#ifdef DEBUG
++ printk(KERN_DEBUG "*** made it back from resume\n");
++#endif
++
++ leds_event(led_start);
++
++ sti();
++
++ return 0;
++}
++
++unsigned long sleep_phys_sp(void *sp)
++{
++ return virt_to_phys(sp);
++}
++
++#ifdef CONFIG_SYSCTL
++/*
++ * ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than
++ * linux/sysctl.h.
++ *
++ * This means our interface here won't survive long - it needs a new
++ * interface. Quick hack to get this working - use sysctl id 9999.
++ */
++#warning ACPI broke the kernel, this interface needs to be fixed up.
++#define CTL_ACPI 9999
++#define ACPI_S1_SLP_TYP 19
++
++/*
++ * Send us to sleep.
++ */
++static int sysctl_pm_do_suspend(void)
++{
++ int retval;
++
++ retval = pm_send_all(PM_SUSPEND, (void *)3);
++
++ if (retval == 0) {
++ retval = pm_do_suspend();
++
++ pm_send_all(PM_RESUME, (void *)0);
++ }
++
++ return retval;
++}
++
++static struct ctl_table pm_table[] =
++{
++ {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend},
++ {0}
++};
++
++static struct ctl_table pm_dir_table[] =
++{
++ {CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
++ {0}
++};
++
++/*
++ * Initialize power interface
++ */
++static int __init pm_init(void)
++{
++ register_sysctl_table(pm_dir_table, 1);
++ return 0;
++}
++
++__initcall(pm_init);
++
++#endif
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/pxa_usb.h
+@@ -0,0 +1,230 @@
++/*
++ * pxa_usb.h
++ *
++ * Public interface to the pxa USB core. For use by client modules
++ * like usb-eth and usb-char.
++ *
++ * 02-May-2002
++ * Frank Becker (Intrinsyc) - derived from sa1100_usb.h
++ *
++ */
++
++#ifndef _PXA_USB_H
++#define _PXA_USB_H
++#include <asm/byteorder.h>
++
++typedef void (*usb_callback_t)(int flag, int size);
++
++/* in usb_ctl.c (see also descriptor methods at bottom of file) */
++
++// Open the USB client for client and initialize data structures
++// to default values, but _do not_ start UDC.
++int pxa_usb_open( const char * client_name );
++
++// Start UDC running
++int pxa_usb_start( void );
++
++// Immediately stop udc, fire off completion routines w/-EINTR
++int pxa_usb_stop( void ) ;
++
++// Disconnect client from usb core
++int pxa_usb_close( void ) ;
++
++// set notify callback for when core reaches configured state
++// return previous pointer (if any)
++typedef void (*usb_notify_t)(void);
++usb_notify_t pxa_set_configured_callback( usb_notify_t callback );
++
++/* in usb_send.c */
++int pxa_usb_xmitter_avail( void );
++int pxa_usb_send(char *buf, int len, usb_callback_t callback);
++void sa110a_usb_send_reset(void);
++
++/* in usb_recev.c */
++int pxa_usb_recv(char *buf, int len, usb_callback_t callback);
++void pxa_usb_recv_reset(void);
++
++//////////////////////////////////////////////////////////////////////////////
++// Descriptor Management
++//////////////////////////////////////////////////////////////////////////////
++
++#define DescriptorHeader \
++ __u8 bLength; \
++ __u8 bDescriptorType
++
++
++// --- Device Descriptor -------------------
++
++typedef struct {
++ DescriptorHeader;
++ __u16 bcdUSB; /* USB specification revision number in BCD */
++ __u8 bDeviceClass; /* USB class for entire device */
++ __u8 bDeviceSubClass; /* USB subclass information for entire device */
++ __u8 bDeviceProtocol; /* USB protocol information for entire device */
++ __u8 bMaxPacketSize0; /* Max packet size for endpoint zero */
++ __u16 idVendor; /* USB vendor ID */
++ __u16 idProduct; /* USB product ID */
++ __u16 bcdDevice; /* vendor assigned device release number */
++ __u8 iManufacturer; /* index of manufacturer string */
++ __u8 iProduct; /* index of string that describes product */
++ __u8 iSerialNumber; /* index of string containing device serial number */
++ __u8 bNumConfigurations; /* number fo configurations */
++} __attribute__ ((packed)) device_desc_t;
++
++// --- Configuration Descriptor ------------
++
++typedef struct {
++ DescriptorHeader;
++ __u16 wTotalLength; /* total # of bytes returned in the cfg buf 4 this cfg */
++ __u8 bNumInterfaces; /* number of interfaces in this cfg */
++ __u8 bConfigurationValue; /* used to uniquely ID this cfg */
++ __u8 iConfiguration; /* index of string describing configuration */
++ __u8 bmAttributes; /* bitmap of attributes for ths cfg */
++ __u8 MaxPower; /* power draw in 2ma units */
++} __attribute__ ((packed)) config_desc_t;
++
++// bmAttributes:
++enum {
++ USB_CONFIG_REMOTEWAKE=0x20,
++ USB_CONFIG_SELFPOWERED=0x40,
++ USB_CONFIG_BUSPOWERED=0x80
++};
++
++// MaxPower:
++#define USB_POWER( x) ((x)>>1) /* convert mA to descriptor units of A for MaxPower */
++
++// --- Interface Descriptor ---------------
++
++typedef struct {
++ DescriptorHeader;
++ __u8 bInterfaceNumber; /* Index uniquely identfying this interface */
++ __u8 bAlternateSetting; /* ids an alternate setting for this interface */
++ __u8 bNumEndpoints; /* number of endpoints in this interface */
++ __u8 bInterfaceClass; /* USB class info applying to this interface */
++ __u8 bInterfaceSubClass; /* USB subclass info applying to this interface */
++ __u8 bInterfaceProtocol; /* USB protocol info applying to this interface */
++ __u8 iInterface; /* index of string describing interface */
++} __attribute__ ((packed)) intf_desc_t;
++
++// --- Endpoint Descriptor ---------------
++
++typedef struct {
++ DescriptorHeader;
++ __u8 bEndpointAddress; /* 0..3 ep num, bit 7: 0 = 0ut 1= in */
++ __u8 bmAttributes; /* 0..1 = 0: ctrl, 1: isoc, 2: bulk 3: intr */
++ __u16 wMaxPacketSize; /* data payload size for this ep in this cfg */
++ __u8 bInterval; /* polling interval for this ep in this cfg */
++} __attribute__ ((packed)) ep_desc_t;
++
++// bEndpointAddress:
++enum {
++ USB_OUT =0,
++ USB_IN =1
++};
++
++#define USB_EP_ADDRESS(a,d) (((a)&0xf) | ((d) << 7))
++// bmAttributes:
++enum {
++ USB_EP_CNTRL =0,
++ USB_EP_BULK =2,
++ USB_EP_INT =3,
++ USB_EP_ISO =4
++};
++
++// --- String Descriptor -------------------
++
++typedef struct {
++ DescriptorHeader;
++ __u16 bString[1]; /* unicode string .. actaully 'n' __u16s */
++} __attribute__ ((packed)) string_desc_t;
++
++/*=======================================================
++ * Handy helpers when working with above
++ *
++ */
++// these are x86-style 16 bit "words" ...
++#define make_word_c( w ) __constant_cpu_to_le16(w)
++#define make_word( w ) __cpu_to_le16(w)
++
++// descriptor types
++enum {
++ USB_DESC_DEVICE = 1,
++ USB_DESC_CONFIG = 2,
++ USB_DESC_STRING = 3,
++ USB_DESC_INTERFACE = 4,
++ USB_DESC_ENDPOINT = 5
++};
++
++
++/*=======================================================
++ * Default descriptor layout for SA-1100 and SA-1110 UDC
++ */
++
++enum {
++ UNUSED = 0,
++
++ BULK_IN1 = 1,
++ BULK_OUT1 = 2,
++ ISO_IN1 = 3,
++ ISO_OUT1 = 4,
++ INT_IN1 = 5,
++
++ BULK_IN2 = 6,
++ BULK_OUT2 = 7,
++ ISO_IN2 = 8,
++ ISO_OUT2 = 9,
++ INT_IN2 = 10,
++
++ BULK_IN3 = 11,
++ BULK_OUT3 = 12,
++ ISO_IN3 = 13,
++ ISO_OUT3 = 14,
++ INT_IN3 = 15
++} /*endpoint_type*/;
++
++/* "config descriptor buffer" - that is, one config,
++ ..one interface and 2 endpoints */
++struct cdb {
++ config_desc_t cfg;
++ intf_desc_t intf;
++ ep_desc_t ep1;
++ ep_desc_t ep2;
++} __attribute__ ((packed));
++
++/* all SA device descriptors */
++typedef struct {
++ device_desc_t dev; /* device descriptor */
++ struct cdb b; /* bundle of descriptors for this cfg */
++} __attribute__ ((packed)) desc_t;
++
++
++/*=======================================================
++ * Descriptor API
++ */
++
++/* Get the address of the statically allocated desc_t structure
++ in the usb core driver. Clients can modify this between
++ the time they call pxa_usb_open() and pxa_usb_start()
++*/
++desc_t *
++pxa_usb_get_descriptor_ptr( void );
++
++
++/* Set a pointer to the string descriptor at "index". The driver
++ ..has room for 8 string indicies internally. Index zero holds
++ ..a LANGID code and is set to US English by default. Inidices
++ ..1-7 are available for use in the config descriptors as client's
++ ..see fit. This pointer is assumed to be good as long as the
++ ..SA usb core is open (so statically allocate them). Returnes -EINVAL
++ ..if index out of range */
++int pxa_usb_set_string_descriptor( int index, string_desc_t * p );
++
++/* reverse of above */
++string_desc_t *
++pxa_usb_get_string_descriptor( int index );
++
++/* kmalloc() a string descriptor and convert "p" to unicode in it */
++string_desc_t *
++pxa_usb_kmalloc_string_descriptor( const char * p );
++
++#endif /* _PXA_USB_H */
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/sa1111.c
+@@ -0,0 +1,3 @@
++#include "../mach-sa1100/sa1111.c"
++
++
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/sa1111.h
+@@ -0,0 +1,2 @@
++#include "../mach-sa1100/sa1111.h"
++
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/sleep.S
+@@ -0,0 +1,150 @@
++/*
++ * Low-level PXA250/210 sleep/wakeUp support
++ *
++ * Initial SA1110 code:
++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
++ *
++ * Adapted for PXA by Nicolas Pitre:
++ * Copyright (c) 2002 Monta Vista Software, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ */
++
++#include <linux/config.h>
++#include <linux/linkage.h>
++#include <asm/assembler.h>
++#include <asm/hardware.h>
++
++ .text
++
++/*
++ * pxa_cpu_suspend()
++ *
++ * Forces CPU into sleep state
++ */
++
++ENTRY(pxa_cpu_suspend)
++
++ mra r2, r3, acc0
++ stmfd sp!, {r2 - r12, lr} @ save registers on stack
++
++ @ get coprocessor registers
++ mrc p15, 0, r4, c15, c1, 0 @ CP access reg
++ mrc p15, 0, r5, c13, c0, 0 @ PID
++ mrc p15, 0, r6, c3, c0, 0 @ domain ID
++ mrc p15, 0, r7, c2, c0, 0 @ translation table base addr
++ mrc p15, 0, r8, c1, c1, 0 @ auxiliary control reg
++ mrc p15, 0, r9, c1, c0, 0 @ control reg
++
++ @ store them plus current virtual stack ptr on stack
++ mov r10, sp
++ stmfd sp!, {r4 - r10}
++
++ @ preserve phys address of stack
++ mov r0, sp
++ bl sleep_phys_sp
++ ldr r1, =sleep_save_sp
++ str r0, [r1]
++
++ @ clean data cache
++ bl cpu_xscale_cache_clean_invalidate_all
++
++ @ Put the processor to sleep
++ @ (also workaround for sighting 28071)
++
++ @ prepare value for sleep mode
++ mov r1, #3 @ sleep mode
++
++ @ prepare to put SDRAM into self-refresh manually
++ ldr r4, =MDREFR
++ ldr r5, [r4]
++ orr r5, r5, #MDREFR_SLFRSH
++
++ @ prepare pointer to physical address 0 (virtual mapping in generic.c)
++ mov r2, #UNCACHED_PHYS_0
++
++ @ align execution to a cache line
++ b 1f
++
++ .ltorg
++ .align 5
++1:
++
++ @ All needed values are now in registers.
++ @ These last instructions should be in cache
++
++ @ put SDRAM into self-refresh
++ str r5, [r4]
++
++ @ force address lines low by reading at physical address 0
++ ldr r3, [r2]
++
++ @ enter sleep mode
++ mcr p14, 0, r1, c7, c0, 0
++
++20: nop
++ b 20b @ loop waiting for sleep
++
++/*
++ * cpu_pxa_resume()
++ *
++ * entry point from bootloader into kernel during resume
++ *
++ * Note: Yes, part of the following code is located into the .data section.
++ * This is to allow sleep_save_sp to be accessed with a relative load
++ * while we can't rely on any MMU translation. We could have put
++ * sleep_save_sp in the .text section as well, but some setups might
++ * insist on it to be truely read-only.
++ */
++
++ .data
++ .align 5
++ENTRY(pxa_cpu_resume)
++ mov r0, #I_BIT | F_BIT | MODE_SVC @ set SVC, irqs off
++ msr cpsr_c, r0
++
++ ldr r0, sleep_save_sp @ stack phys addr
++ ldr r2, =resume_after_mmu @ its absolute virtual address
++ ldmfd r0, {r4 - r9, sp} @ CP regs + virt stack ptr
++
++ mov r1, #0
++ mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
++ mcr p15, 0, r1, c7, c7, 0 @ invalidate I & D caches, BTB
++
++#ifdef CONFIG_XSCALE_CACHE_ERRATA
++ bic r9, r9, #0x0004 @ see cpu_xscale_proc_init
++#endif
++
++ mcr p15, 0, r4, c15, c1, 0 @ CP access reg
++ mcr p15, 0, r5, c13, c0, 0 @ PID
++ mcr p15, 0, r6, c3, c0, 0 @ domain ID
++ mcr p15, 0, r7, c2, c0, 0 @ translation table base addr
++ mcr p15, 0, r8, c1, c1, 0 @ auxiliary control reg
++ b resume_turn_on_mmu @ cache align execution
++
++ .align 5
++resume_turn_on_mmu:
++ mcr p15, 0, r9, c1, c0, 0 @ turn on MMU, caches, etc.
++
++ @ Let us ensure we jump to resume_after_mmu only when the mcr above
++ @ actually took effect. They call it the "cpwait" operation.
++ mrc p15, 0, r1, c2, c0, 0 @ queue a dependency on CP15
++ sub pc, r2, r1, lsr #32 @ jump to virtual addr
++ nop
++ nop
++ nop
++
++sleep_save_sp:
++ .word 0 @ preserve stack phys ptr here
++
++ .text
++resume_after_mmu:
++#ifdef CONFIG_XSCALE_CACHE_ERRATA
++ bl cpu_xscale_proc_init
++#endif
++ ldmfd sp!, {r2, r3}
++ mar acc0, r2, r3
++ ldmfd sp!, {r4 - r12, pc} @ return to caller
++
++
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/trizeps2.c
+@@ -0,0 +1,105 @@
++/*
++ * linux/arch/arm/mach-pxa/trizeps2.c
++ *
++ * Support for the Keith&Koep MT6N Development Platform.
++ *
++ * Author: Luc De Cock
++ * Created: Jan 13, 2003
++ * Copyright: Teradyne DS, Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/init.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/arch/irq.h>
++
++#include "generic.h"
++
++static unsigned long trizeps2_irq_en_mask;
++unsigned short trizeps2_bcr_shadow = 0x50; // 0x70
++
++
++static void __init trizeps2_init_irq(void)
++{
++ int irq;
++
++ pxa_init_irq();
++
++ set_GPIO_IRQ_edge(GPIO_ETHERNET_IRQ, GPIO_RISING_EDGE);
++}
++
++static int __init trizeps2_init(void)
++{
++ /* Configure the BCR register */
++ unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE;
++
++ *bcr = trizeps2_bcr_shadow;
++ return 0;
++}
++
++__initcall(trizeps2_init);
++
++static void __init
++fixup_trizeps2(struct machine_desc *desc, struct param_struct *params,
++ char **cmdline, struct meminfo *mi)
++{
++#ifdef TRIZEPS2_MEM_64MB
++ SET_BANK (0, 0xa0000000, 64*1024*1024);
++#else
++ SET_BANK (0, 0xa0000000, 32*1024*1024);
++#endif
++ mi->nr_banks = 1;
++}
++
++static struct map_desc trizeps2_io_desc[] __initdata = {
++ /* virtual physical length domain r w c b */
++ { 0xf0000000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* BCR */
++ { 0xf0100000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA STATUS */
++ { 0xf1000000, 0x0c800000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO */
++ { 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr */
++ { 0xf2000000, 0x0d800000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* TTL-IO */
++ LAST_DESC
++};
++
++static void __init trizeps2_map_io(void)
++{
++ pxa_map_io();
++ iotable_init(trizeps2_io_desc);
++
++ /* This is for the SMC chip select */
++ set_GPIO_mode(GPIO79_nCS_3_MD);
++
++ /* setup sleep mode values */
++ PWER = 0x00000002;
++ PFER = 0x00000000;
++ PRER = 0x00000002;
++ PGSR0 = 0x00008000;
++ PGSR1 = 0x003F0202;
++ PGSR2 = 0x0001C000;
++ PCFR |= PCFR_OPDE;
++}
++
++MACHINE_START(TRIZEPS2, "Keith-n-Koep MT6N Development Platform")
++ MAINTAINER("Luc De Cock")
++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
++ FIXUP(fixup_trizeps2)
++ MAPIO(trizeps2_map_io)
++ INITIRQ(trizeps2_init_irq)
++MACHINE_END
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/usb-char.c
+@@ -0,0 +1,719 @@
++/*
++ * (C) Copyright 2000-2001 Extenex Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * usb-char.c
++ *
++ * Miscellaneous character device interface for SA1100 USB function
++ * driver.
++ *
++ * Background:
++ * The SA1100 function driver ported from the Compaq Itsy project
++ * has an interface, usb-eth.c, to feed network packets over the
++ * usb wire and into the Linux TCP/IP stack.
++ *
++ * This file replaces that one with a simple character device
++ * interface that allows unstructured "byte pipe" style reads and
++ * writes over the USB bulk endpoints by userspace programs.
++ *
++ * A new define, CONFIG_SA1100_USB_NETLINK, has been created that,
++ * when set, (the default) causes the ethernet interface to be used.
++ * When not set, this more pedestrian character interface is linked
++ * in instead.
++ *
++ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
++ *
++ * ward.willats@extenex.com
++ *
++ * To do:
++ * - Can't dma into ring buffer directly with pci_map/unmap usb_recv
++ * uses and get bytes out at the same time DMA is going on. Investigate:
++ * a) changing usb_recv to use alloc_consistent() at client request; or
++ * b) non-ring-buffer based data structures. In the meantime, I am using
++ * a bounce buffer. Simple, but wasteful.
++ */
++
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/miscdevice.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/cache.h>
++#include <linux/poll.h>
++#include <linux/circ_buf.h>
++#include <linux/timer.h>
++
++#include <asm/io.h>
++#include <asm/semaphore.h>
++#include <asm/proc/page.h>
++#include <asm/mach-types.h>
++
++#include "usb-char.h"
++#include "pxa_usb.h"
++
++
++
++//////////////////////////////////////////////////////////////////////////////
++// Driver Options
++//////////////////////////////////////////////////////////////////////////////
++
++#define VERSION "0.4"
++
++
++#define VERBOSITY 1
++
++#if VERBOSITY
++# define PRINTK(x, a...) printk (x, ## a)
++#else
++# define PRINTK(x, a...) /**/
++#endif
++
++//////////////////////////////////////////////////////////////////////////////
++// Globals - Macros - Enums - Structures
++//////////////////////////////////////////////////////////////////////////////
++#ifndef MIN
++#define MIN( a, b ) ((a)<(b)?(a):(b))
++#endif
++
++typedef int bool; enum { false = 0, true = 1 };
++
++static const char pszMe[] = "usbchr: ";
++
++static wait_queue_head_t wq_read;
++static wait_queue_head_t wq_write;
++static wait_queue_head_t wq_poll;
++
++/* Serialze multiple writers onto the transmit hardware
++.. since we sleep the writer during transmit to stay in
++.. sync. (Multiple writers don't make much sense, but..) */
++static DECLARE_MUTEX( xmit_sem );
++
++// size of usb DATA0/1 packets. 64 is standard maximum
++// for bulk transport, though most hosts seem to be able
++// to handle larger.
++#define TX_PACKET_SIZE 64
++#define RX_PACKET_SIZE 64
++#define RBUF_SIZE (4*PAGE_SIZE)
++
++static struct wcirc_buf {
++ char *buf;
++ int in;
++ int out;
++} rx_ring = { NULL, 0, 0 };
++
++static struct {
++ unsigned long cnt_rx_complete;
++ unsigned long cnt_rx_errors;
++ unsigned long bytes_rx;
++ unsigned long cnt_tx_timeouts;
++ unsigned long cnt_tx_errors;
++ unsigned long bytes_tx;
++} charstats;
++
++
++static char * tx_buf = NULL;
++static char * packet_buffer = NULL;
++static int sending = 0;
++static int usb_ref_count = 0;
++static int last_tx_result = 0;
++static int last_rx_result = 0;
++static int last_tx_size = 0;
++static struct timer_list tx_timer;
++
++//////////////////////////////////////////////////////////////////////////////
++// Prototypes
++//////////////////////////////////////////////////////////////////////////////
++static char * what_the_f( int e );
++static void free_txrx_buffers( void );
++static void twiddle_descriptors( void );
++static void free_string_descriptors( void ) ;
++static int usbc_open( struct inode *pInode, struct file *pFile );
++static void rx_done_callback_packet_buffer( int flag, int size );
++
++static void tx_timeout( unsigned long );
++static void tx_done_callback( int flag, int size );
++
++static ssize_t usbc_read( struct file *, char *, size_t, loff_t * );
++static ssize_t usbc_write( struct file *, const char *, size_t, loff_t * );
++static unsigned int usbc_poll( struct file *pFile, poll_table * pWait );
++static int usbc_ioctl( struct inode *pInode, struct file *pFile,
++ unsigned int nCmd, unsigned long argument );
++static int usbc_close( struct inode *pInode, struct file *pFile );
++
++#ifdef CONFIG_SA1100_EXTENEX1
++static void extenex_configured_notify_proc( void );
++#endif
++//////////////////////////////////////////////////////////////////////////////
++// Private Helpers
++//////////////////////////////////////////////////////////////////////////////
++
++static char * what_the_f( int e )
++{
++ char * p;
++ switch( e ) {
++ case 0:
++ p = "noErr";
++ break;
++ case -ENODEV:
++ p = "ENODEV - usb not in config state";
++ break;
++ case -EBUSY:
++ p = "EBUSY - another request on the hardware";
++ break;
++ case -EAGAIN:
++ p = "EAGAIN";
++ break;
++ case -EINTR:
++ p = "EINTR - interrupted\n";
++ break;
++ case -EPIPE:
++ p = "EPIPE - zero length xfer\n";
++ break;
++ default:
++ p = "????";
++ break;
++ }
++ return p;
++}
++
++static void free_txrx_buffers( void )
++{
++ if ( rx_ring.buf != NULL ) {
++ kfree( rx_ring.buf );
++ rx_ring.buf = NULL;
++ }
++ if ( packet_buffer != NULL ) {
++ kfree( packet_buffer );
++ packet_buffer = NULL;
++ }
++ if ( tx_buf != NULL ) {
++ kfree( tx_buf );
++ tx_buf = NULL;
++ }
++}
++
++/* twiddle_descriptors()
++ * It is between open() and start(). Setup descriptors.
++ */
++static void twiddle_descriptors( void )
++{
++ desc_t * pDesc = pxa_usb_get_descriptor_ptr();
++ string_desc_t * pString;
++
++ pDesc->b.ep1.wMaxPacketSize = make_word_c( RX_PACKET_SIZE );
++ pDesc->b.ep1.bmAttributes = USB_EP_BULK;
++ pDesc->b.ep2.wMaxPacketSize = make_word_c( TX_PACKET_SIZE );
++ pDesc->b.ep2.bmAttributes = USB_EP_BULK;
++
++ if ( machine_is_extenex1() ) {
++#ifdef CONFIG_SA1100_EXTENEX1
++ pDesc->dev.idVendor = make_word_c( 0xC9F );
++ pDesc->dev.idProduct = 1;
++ pDesc->dev.bcdDevice = make_word_c( 0x0001 );
++ pDesc->b.cfg.bmAttributes = USB_CONFIG_SELFPOWERED;
++ pDesc->b.cfg.MaxPower = 0;
++
++ pString = pxa_usb_kmalloc_string_descriptor( "Extenex" );
++ if ( pString ) {
++ pxa_usb_set_string_descriptor( 1, pString );
++ pDesc->dev.iManufacturer = 1;
++ }
++
++ pString = pxa_usb_kmalloc_string_descriptor( "Handheld Theater" );
++ if ( pString ) {
++ pxa_usb_set_string_descriptor( 2, pString );
++ pDesc->dev.iProduct = 2;
++ }
++
++ pString = pxa_usb_kmalloc_string_descriptor( "00000000" );
++ if ( pString ) {
++ pxa_usb_set_string_descriptor( 3, pString );
++ pDesc->dev.iSerialNumber = 3;
++ }
++
++ pString = pxa_usb_kmalloc_string_descriptor( "HHT Bulk Transfer" );
++ if ( pString ) {
++ pxa_usb_set_string_descriptor( 4, pString );
++ pDesc->b.intf.iInterface = 4;
++ }
++ pxa_set_configured_callback( extenex_configured_notify_proc );
++#endif
++ }
++}
++
++static void free_string_descriptors( void )
++{
++ if ( machine_is_extenex1() ) {
++ string_desc_t * pString;
++ int i;
++ for( i = 1 ; i <= 4 ; i++ ) {
++ pString = pxa_usb_get_string_descriptor( i );
++ if ( pString )
++ kfree( pString );
++ }
++ }
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// ASYNCHRONOUS
++//////////////////////////////////////////////////////////////////////////////
++static void kick_start_rx( void )
++{
++ if ( usb_ref_count ) {
++ int total_space = CIRC_SPACE( rx_ring.in, rx_ring.out, RBUF_SIZE );
++ if ( total_space >= RX_PACKET_SIZE ) {
++ pxa_usb_recv( packet_buffer,
++ RX_PACKET_SIZE,
++ rx_done_callback_packet_buffer
++ );
++ }
++ }
++}
++/*
++ * rx_done_callback_packet_buffer()
++ * We have completed a DMA xfer into the temp packet buffer.
++ * Move to ring.
++ *
++ * flag values:
++ * on init, -EAGAIN
++ * on reset, -EINTR
++ * on RPE, -EIO
++ * on short packet -EPIPE
++ */
++static void
++rx_done_callback_packet_buffer( int flag, int size )
++{
++ charstats.cnt_rx_complete++;
++
++ if ( flag == 0 || flag == -EPIPE ) {
++ size_t n;
++
++ charstats.bytes_rx += size;
++
++ n = CIRC_SPACE_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE );
++ n = MIN( n, size );
++ size -= n;
++
++ memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer, n );
++ rx_ring.in = (rx_ring.in + n) & (RBUF_SIZE-1);
++ memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer + n, size );
++ rx_ring.in = (rx_ring.in + size) & (RBUF_SIZE-1);
++
++ wake_up_interruptible( &wq_read );
++ wake_up_interruptible( &wq_poll );
++
++ last_rx_result = 0;
++
++ kick_start_rx();
++
++ } else if ( flag != -EAGAIN ) {
++ charstats.cnt_rx_errors++;
++ last_rx_result = flag;
++ wake_up_interruptible( &wq_read );
++ wake_up_interruptible( &wq_poll );
++ }
++ else /* init, start a read */
++ kick_start_rx();
++}
++
++
++static void tx_timeout( unsigned long unused )
++{
++ printk( "%stx timeout\n", pszMe );
++ pxa_usb_send_reset();
++ charstats.cnt_tx_timeouts++;
++}
++
++
++// on init, -EAGAIN
++// on reset, -EINTR
++// on TPE, -EIO
++static void tx_done_callback( int flags, int size )
++{
++ if ( flags == 0 )
++ charstats.bytes_tx += size;
++ else
++ charstats.cnt_tx_errors++;
++ last_tx_size = size;
++ last_tx_result = flags;
++ sending = 0;
++ wake_up_interruptible( &wq_write );
++ wake_up_interruptible( &wq_poll );
++}
++
++
++//////////////////////////////////////////////////////////////////////////////
++// Workers
++//////////////////////////////////////////////////////////////////////////////
++
++static int usbc_open( struct inode *pInode, struct file *pFile )
++{
++ int retval = 0;
++
++ PRINTK( KERN_DEBUG "%sopen()\n", pszMe );
++
++ /* start usb core */
++ retval = pxa_usb_open( "usb-char" );
++ if ( retval ) return retval;
++
++ /* allocate memory */
++ if ( usb_ref_count == 0 ) {
++ tx_buf = (char*) kmalloc( TX_PACKET_SIZE, GFP_KERNEL | GFP_DMA );
++ if ( tx_buf == NULL ) {
++ printk( "%sARGHH! COULD NOT ALLOCATE TX BUFFER\n", pszMe );
++ goto malloc_fail;
++ }
++ rx_ring.buf =
++ (char*) kmalloc( RBUF_SIZE, GFP_KERNEL );
++
++ if ( rx_ring.buf == NULL ) {
++ printk( "%sARGHH! COULD NOT ALLOCATE RX BUFFER\n", pszMe );
++ goto malloc_fail;
++ }
++
++ packet_buffer =
++ (char*) kmalloc( RX_PACKET_SIZE, GFP_KERNEL | GFP_DMA );
++
++ if ( packet_buffer == NULL ) {
++ printk( "%sARGHH! COULD NOT ALLOCATE RX PACKET BUFFER\n", pszMe );
++ goto malloc_fail;
++ }
++ rx_ring.in = rx_ring.out = 0;
++ memset( &charstats, 0, sizeof( charstats ) );
++ sending = 0;
++ last_tx_result = 0;
++ last_tx_size = 0;
++ }
++
++ /* modify default descriptors */
++ twiddle_descriptors();
++
++ retval = pxa_usb_start();
++ if ( retval ) {
++ printk( "%sAGHH! Could not USB core\n", pszMe );
++ free_txrx_buffers();
++ return retval;
++ }
++ usb_ref_count++; /* must do _before_ kick_start() */
++ MOD_INC_USE_COUNT;
++ kick_start_rx();
++ return 0;
++
++ malloc_fail:
++ free_txrx_buffers();
++ return -ENOMEM;
++}
++
++/*
++ * Read endpoint. Note that you can issue a read to an
++ * unconfigured endpoint. Eventually, the host may come along
++ * and configure underneath this module and data will appear.
++ */
++static ssize_t usbc_read( struct file *pFile, char *pUserBuffer,
++ size_t stCount, loff_t *pPos )
++{
++ ssize_t retval;
++ int flags;
++ DECLARE_WAITQUEUE( wait, current );
++
++ PRINTK( KERN_DEBUG "%sread()\n", pszMe );
++
++ local_irq_save( flags );
++ if ( last_rx_result == 0 ) {
++ local_irq_restore( flags );
++ } else { /* an error happended and receiver is paused */
++ local_irq_restore( flags );
++ last_rx_result = 0;
++ kick_start_rx();
++ }
++
++ add_wait_queue( &wq_read, &wait );
++ while( 1 ) {
++ ssize_t bytes_avail;
++ ssize_t bytes_to_end;
++
++ set_current_state( TASK_INTERRUPTIBLE );
++
++ /* snap ring buf state */
++ local_irq_save( flags );
++ bytes_avail = CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE );
++ bytes_to_end = CIRC_CNT_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE );
++ local_irq_restore( flags );
++
++ if ( bytes_avail != 0 ) {
++ ssize_t bytes_to_move = MIN( stCount, bytes_avail );
++ retval = 0; // will be bytes transfered
++ if ( bytes_to_move != 0 ) {
++ size_t n = MIN( bytes_to_end, bytes_to_move );
++ if ( copy_to_user( pUserBuffer,
++ &rx_ring.buf[ rx_ring.out ],
++ n ) ) {
++ retval = -EFAULT;
++ break;
++ }
++ bytes_to_move -= n;
++ retval += n;
++ // might go 1 char off end, so wrap
++ rx_ring.out = ( rx_ring.out + n ) & (RBUF_SIZE-1);
++ if ( copy_to_user( pUserBuffer + n,
++ &rx_ring.buf[ rx_ring.out ],
++ bytes_to_move )
++ ) {
++ retval = -EFAULT;
++ break;
++ }
++ rx_ring.out += bytes_to_move; // cannot wrap
++ retval += bytes_to_move;
++ kick_start_rx();
++ }
++ break;
++ }
++ else if ( last_rx_result ) {
++ retval = last_rx_result;
++ break;
++ }
++ else if ( pFile->f_flags & O_NONBLOCK ) { // no data, can't sleep
++ retval = -EAGAIN;
++ break;
++ }
++ else if ( signal_pending( current ) ) { // no data, can sleep, but signal
++ retval = -ERESTARTSYS;
++ break;
++ }
++ schedule(); // no data, can sleep
++ }
++ set_current_state( TASK_RUNNING );
++ remove_wait_queue( &wq_read, &wait );
++
++ if ( retval < 0 )
++ printk( "%sread error %d - %s\n", pszMe, retval, what_the_f( retval ) );
++ return retval;
++}
++
++/*
++ * Write endpoint. This routine attempts to break the passed in buffer
++ * into usb DATA0/1 packet size chunks and send them to the host.
++ * (The lower-level driver tries to do this too, but easier for us
++ * to manage things here.)
++ *
++ * We are at the mercy of the host here, in that it must send an IN
++ * token to us to pull this data back, so hopefully some higher level
++ * protocol is expecting traffic to flow in that direction so the host
++ * is actually polling us. To guard against hangs, a 5 second timeout
++ * is used.
++ *
++ * This routine takes some care to only report bytes sent that have
++ * actually made it across the wire. Thus we try to stay in lockstep
++ * with the completion routine and only have one packet on the xmit
++ * hardware at a time. Multiple simultaneous writers will get
++ * "undefined" results.
++ *
++ */
++static ssize_t usbc_write( struct file *pFile, const char * pUserBuffer,
++ size_t stCount, loff_t *pPos )
++{
++ ssize_t retval = 0;
++ ssize_t stSent = 0;
++
++ DECLARE_WAITQUEUE( wait, current );
++
++ PRINTK( KERN_DEBUG "%swrite() %d bytes\n", pszMe, stCount );
++
++ down( &xmit_sem ); // only one thread onto the hardware at a time
++
++ while( stCount != 0 && retval == 0 ) {
++ int nThisTime = MIN( TX_PACKET_SIZE, stCount );
++ copy_from_user( tx_buf, pUserBuffer, nThisTime );
++ sending = nThisTime;
++ retval = pxa_usb_send( tx_buf, nThisTime, tx_done_callback );
++ if ( retval < 0 ) {
++ char * p = what_the_f( retval );
++ printk( "%sCould not queue xmission. rc=%d - %s\n",
++ pszMe, retval, p );
++ sending = 0;
++ break;
++ }
++ /* now have something on the diving board */
++ add_wait_queue( &wq_write, &wait );
++ tx_timer.expires = jiffies + ( HZ * 5 );
++ add_timer( &tx_timer );
++ while( 1 ) {
++ set_current_state( TASK_INTERRUPTIBLE );
++ if ( sending == 0 ) { /* it jumped into the pool */
++ del_timer( &tx_timer );
++ retval = last_tx_result;
++ if ( retval == 0 ) {
++ stSent += last_tx_size;
++ pUserBuffer += last_tx_size;
++ stCount -= last_tx_size;
++ }
++ else
++ printk( "%sxmission error rc=%d - %s\n",
++ pszMe, retval, what_the_f(retval) );
++ break;
++ }
++ else if ( signal_pending( current ) ) {
++ del_timer( &tx_timer );
++ printk( "%ssignal\n", pszMe );
++ retval = -ERESTARTSYS;
++ break;
++ }
++ schedule();
++ }
++ set_current_state( TASK_RUNNING );
++ remove_wait_queue( &wq_write, &wait );
++ }
++
++ up( &xmit_sem );
++
++ if ( 0 == retval )
++ retval = stSent;
++ return retval;
++}
++
++static unsigned int usbc_poll( struct file *pFile, poll_table * pWait )
++{
++ unsigned int retval = 0;
++
++ PRINTK( KERN_DEBUG "%poll()\n", pszMe );
++
++ poll_wait( pFile, &wq_poll, pWait );
++
++ if ( CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ) )
++ retval |= POLLIN | POLLRDNORM;
++ if ( pxa_usb_xmitter_avail() )
++ retval |= POLLOUT | POLLWRNORM;
++ return retval;
++}
++
++static int usbc_ioctl( struct inode *pInode, struct file *pFile,
++ unsigned int nCmd, unsigned long argument )
++{
++ int retval = 0;
++
++ switch( nCmd ) {
++
++ case USBC_IOC_FLUSH_RECEIVER:
++ pxa_usb_recv_reset();
++ rx_ring.in = rx_ring.out = 0;
++ break;
++
++ case USBC_IOC_FLUSH_TRANSMITTER:
++ pxa_usb_send_reset();
++ break;
++
++ case USBC_IOC_FLUSH_ALL:
++ pxa_usb_recv_reset();
++ rx_ring.in = rx_ring.out = 0;
++ pxa_usb_send_reset();
++ break;
++
++ default:
++ retval = -ENOIOCTLCMD;
++ break;
++
++ }
++ return retval;
++}
++
++
++static int usbc_close( struct inode *pInode, struct file * pFile )
++{
++ PRINTK( KERN_DEBUG "%sclose()\n", pszMe );
++ if ( --usb_ref_count == 0 ) {
++ down( &xmit_sem );
++ pxa_usb_stop();
++ free_txrx_buffers();
++ free_string_descriptors();
++ del_timer( &tx_timer );
++ pxa_usb_close();
++ up( &xmit_sem );
++ }
++ MOD_DEC_USE_COUNT;
++ return 0;
++}
++
++#ifdef CONFIG_SA1100_EXTENEX1
++#include "../../../drivers/char/ex_gpio.h"
++void extenex_configured_notify_proc( void )
++{
++ if ( exgpio_play_string( "440,1:698,1" ) == -EAGAIN )
++ printk( "%sWanted to BEEP but ex_gpio not open\n", pszMe );
++}
++#endif
++//////////////////////////////////////////////////////////////////////////////
++// Initialization
++//////////////////////////////////////////////////////////////////////////////
++
++static struct file_operations usbc_fops = {
++ owner: THIS_MODULE,
++ open: usbc_open,
++ read: usbc_read,
++ write: usbc_write,
++ poll: usbc_poll,
++ ioctl: usbc_ioctl,
++ release: usbc_close,
++};
++
++static struct miscdevice usbc_misc_device = {
++ USBC_MINOR, "usb_char", &usbc_fops
++};
++
++/*
++ * usbc_init()
++ */
++
++int __init usbc_init( void )
++{
++ int rc;
++
++ if ( (rc = misc_register( &usbc_misc_device )) != 0 ) {
++ printk( KERN_WARNING "%sCould not register device 10, "
++ "%d. (%d)\n", pszMe, USBC_MINOR, rc );
++ return -EBUSY;
++ }
++
++ // initialize wait queues
++ init_waitqueue_head( &wq_read );
++ init_waitqueue_head( &wq_write );
++ init_waitqueue_head( &wq_poll );
++
++ // initialize tx timeout timer
++ init_timer( &tx_timer );
++ tx_timer.function = tx_timeout;
++
++ printk( KERN_INFO "USB Function Character Driver Interface"
++ " - %s, (C) 2001, Extenex Corp.\n", VERSION
++ );
++
++ return rc;
++}
++
++void __exit usbc_exit( void )
++{
++}
++
++EXPORT_NO_SYMBOLS;
++
++module_init(usbc_init);
++module_exit(usbc_exit);
++
++
++
++// end: usb-char.c
++
++
++
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/usb-char.h
+@@ -0,0 +1,34 @@
++/*
++ * Copyright (C) 2001 Extenex Corporation
++ *
++ * usb-char.h
++ *
++ * Character device emulation client for SA-1100 client usb core.
++ *
++ *
++ *
++ */
++#ifndef _USB_CHAR_H
++#define _USB_CHAR_H
++
++#define USBC_MAJOR 10 /* miscellaneous character device */
++#define USBC_MINOR 240 /* in the "reserved for local use" range */
++
++#define USBC_MAGIC 0x8E
++
++/* zap everything in receive ring buffer */
++#define USBC_IOC_FLUSH_RECEIVER _IO( USBC_MAGIC, 0x01 )
++
++/* reset transmitter */
++#define USBC_IOC_FLUSH_TRANSMITTER _IO( USBC_MAGIC, 0x02 )
++
++/* do both of above */
++#define USBC_IOC_FLUSH_ALL _IO( USBC_MAGIC, 0x03 )
++
++
++
++
++
++
++#endif /* _USB_CHAR_H */
++
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/usb-eth.c
+@@ -0,0 +1,479 @@
++/*
++ * Ethernet driver for the PXA USB client function
++ * Copyright (c) 2001 by Nicolas Pitre
++ *
++ * This code was loosely inspired by the original initial ethernet test driver
++ * Copyright (c) Compaq Computer Corporation, 1999
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This is still work in progress...
++ *
++ * 19/02/2001 - Now we are compatible with generic usbnet driver. green@iXcelerator.com
++ * 09/03/2001 - Dropped 'framing' scheme, as it seems to cause a lot of problems with little benefit.
++ * Now, since we do not know what size of packet we are receiving
++ * last usb packet in sequence will always be less than max packet
++ * receive endpoint can accept.
++ * Now the only way to check correct start of frame is to compare
++ * MAC address. Also now we are stalling on each receive error.
++ *
++ * 15/03/2001 - Using buffer to get data from UDC. DMA needs to have 8 byte
++ * aligned buffer, but this breaks IP code (unaligned access).
++ *
++ * 01/04/2001 - stall endpoint operations appeared to be very unstable, so
++ * they are disabled now.
++ *
++ * 03/06/2001 - Readded "zerocopy" receive path (tunable).
++ *
++ */
++
++// Define DMA_NO_COPY if you want data to arrive directly into the
++// receive network buffers, instead of arriving into bounce buffer
++// and then get copied to network buffer.
++// This does not work correctly right now.
++#undef DMA_NO_COPY
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/timer.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/random.h>
++
++#include "pxa_usb.h"
++
++
++#define ETHERNET_VENDOR_ID 0x49f
++#define ETHERNET_PRODUCT_ID 0x505A
++#define MAX_PACKET 32768
++#define MIN(a, b) (((a) < (b)) ? (a) : (b))
++
++// Should be global, so that insmod can change these
++int usb_rsize=64;
++int usb_wsize=64;
++
++static struct usbe_info_t {
++ struct net_device *dev;
++ u16 packet_id;
++ struct net_device_stats stats;
++} usbe_info;
++
++static char usb_eth_name[16] = "usbf";
++static struct net_device usb_eth_device;
++static struct sk_buff *cur_tx_skb, *next_tx_skb;
++static struct sk_buff *cur_rx_skb, *next_rx_skb;
++static volatile int terminating;
++#ifndef DMA_NO_COPY
++static char *dmabuf; // we need that, as dma expect it's buffers to be aligned on 8 bytes boundary
++#endif
++
++static int usb_change_mtu (struct net_device *net, int new_mtu)
++{
++ if (new_mtu <= sizeof (struct ethhdr) || new_mtu > MAX_PACKET)
++ return -EINVAL;
++ // no second zero-length packet read wanted after mtu-sized packets
++ if (((new_mtu + sizeof (struct ethhdr)) % usb_rsize) == 0)
++ return -EDOM;
++
++ net->mtu = new_mtu;
++ return 0;
++}
++
++static struct sk_buff *
++usb_new_recv_skb(void)
++{
++ struct sk_buff *skb = alloc_skb( 2 + sizeof (struct ethhdr) + usb_eth_device.mtu,GFP_ATOMIC);
++
++ if (skb) {
++ skb_reserve(skb, 2);
++ }
++ return skb;
++}
++
++static u8 bcast_hwaddr[ETH_ALEN]={0xff,0xff,0xff,0xff,0xff,0xff};
++static void
++usb_recv_callback(int flag, int size)
++{
++ struct sk_buff *skb;
++
++ if (terminating)
++ return;
++
++ skb = cur_rx_skb;
++
++ /* flag validation */
++ if (flag == 0) {
++ if ( skb_tailroom (skb) < size ) { // hey! we are overloaded!!!
++ usbe_info.stats.rx_over_errors++;
++ goto error;
++ }
++#ifndef DMA_NO_COPY
++ memcpy(skb->tail,dmabuf,size);
++#endif
++ skb_put(skb, size);
++ } else {
++ if (flag == -EIO) {
++ usbe_info.stats.rx_errors++;
++ }
++ goto error;
++ }
++
++
++ /*
++ * If the real size of the packet is divisible by usb_rsize
++ * an extra byte will be added. Thus size == usb_rsize
++ * should only happen if more data is to come.
++ */
++ /* validate packet length */
++ if (size == usb_rsize ) {
++ /* packet not complete yet */
++ skb = NULL;
++ }
++
++ /*
++ * At this point skb is non null if we have a complete packet.
++ * If so take a fresh skb right away and restart USB receive without
++ * further delays, then process the packet. Otherwise resume USB
++ * receive on the current skb and exit.
++ */
++
++ if (skb)
++ cur_rx_skb = next_rx_skb;
++#ifndef DMA_NO_COPY
++ pxa_usb_recv(dmabuf, usb_rsize,
++ usb_recv_callback);
++#else
++ pxa_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)),
++ usb_recv_callback);
++#endif
++ if (!skb)
++ return;
++
++ next_rx_skb = usb_new_recv_skb();
++ if (!next_rx_skb) {
++ /*
++ * We can't aford loosing buffer space...
++ * So we drop the current packet and recycle its skb.
++ */
++ printk("%s: can't allocate new skb\n", __FUNCTION__);
++ usbe_info.stats.rx_dropped++;
++ skb_trim(skb, 0);
++ next_rx_skb = skb;
++ return;
++ }
++ if ( skb->len >= sizeof(struct ethhdr)) {
++ if (memcmp(skb->data,usb_eth_device.dev_addr,ETH_ALEN) && memcmp(skb->data,bcast_hwaddr,ETH_ALEN) ) {
++ // This frame is not for us. nor it is broadcast
++ usbe_info.stats.rx_frame_errors++;
++ kfree_skb(skb);
++ goto error;
++ }
++
++#if 0
++{
++ int i;
++
++ for (i = 0; i < skb->len; i++)
++ {
++ printk("%02X ", skb->data[i]);
++ if( (i%8)==7) printk("\n");
++ }
++ printk("...\n");
++}
++#endif
++
++ }
++
++ if (skb->len) {
++ int status;
++// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ?
++
++ skb->dev = &usb_eth_device;
++ skb->protocol = eth_type_trans (skb, &usb_eth_device);
++ usbe_info.stats.rx_packets++;
++ usbe_info.stats.rx_bytes += skb->len;
++ skb->ip_summed = CHECKSUM_NONE;
++ status = netif_rx (skb);
++ if (status != NET_RX_SUCCESS)
++ printk("netif_rx failed with code %d\n",status);
++ } else {
++error:
++//printk("ERROR... tailroom=%d size=%d len=%d flag=%d\n", skb_tailroom(skb), size, skb->len, flag);
++ /*
++ * Error due to HW addr mismatch, or IO error.
++ * Recycle the current skb and reset USB reception.
++ */
++ skb_trim(cur_rx_skb, 0);
++// if ( flag == -EINTR || flag == -EAGAIN ) // only if we are coming out of stall
++#ifndef DMA_NO_COPY
++ pxa_usb_recv(dmabuf, usb_rsize, usb_recv_callback);
++#else
++ pxa_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)), usb_recv_callback);
++#endif
++ }
++}
++
++
++static void
++usb_send_callback(int flag, int size)
++{
++ struct net_device *dev = usbe_info.dev;
++ struct net_device_stats *stats;
++ struct sk_buff *skb=cur_tx_skb;
++ int ret;
++
++ if (terminating)
++ return;
++
++ stats = &usbe_info.stats;
++ switch (flag) {
++ case 0:
++ stats->tx_packets++;
++ stats->tx_bytes += size;
++ break;
++ case -EIO:
++ stats->tx_errors++;
++ break;
++ default:
++ stats->tx_dropped++;
++ break;
++ }
++
++ cur_tx_skb = next_tx_skb;
++ next_tx_skb = NULL;
++ dev_kfree_skb_irq(skb);
++ if (!cur_tx_skb)
++ return;
++
++ dev->trans_start = jiffies;
++ ret = pxa_usb_send(cur_tx_skb->data, cur_tx_skb->len, usb_send_callback);
++ if (ret) {
++ /* If the USB core can't accept the packet, we drop it. */
++ dev_kfree_skb_irq(cur_tx_skb);
++ cur_tx_skb = NULL;
++ usbe_info.stats.tx_carrier_errors++;
++ }
++ netif_wake_queue(dev);
++}
++
++static int
++usb_eth_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ int ret;
++ long flags;
++
++ if (next_tx_skb) {
++ printk("%s: called with next_tx_skb != NULL\n", __FUNCTION__);
++ return 1;
++ }
++
++ if (skb_shared (skb)) {
++ struct sk_buff *skb2 = skb_unshare(skb, GFP_ATOMIC);
++ if (!skb2) {
++ usbe_info.stats.tx_dropped++;
++ dev_kfree_skb(skb);
++ return 1;
++ }
++ skb = skb2;
++ }
++
++ if ((skb->len % usb_wsize) == 0) {
++ skb->len++; // other side will ignore this one, anyway.
++ }
++
++ save_flags_cli(flags);
++ if (cur_tx_skb) {
++ next_tx_skb = skb;
++ netif_stop_queue(dev);
++ } else {
++ cur_tx_skb = skb;
++ dev->trans_start = jiffies;
++ ret = pxa_usb_send(skb->data, skb->len, usb_send_callback);
++ if (ret) {
++ /* If the USB core can't accept the packet, we drop it. */
++ dev_kfree_skb(skb);
++ cur_tx_skb = NULL;
++ usbe_info.stats.tx_carrier_errors++;
++ }
++ }
++ restore_flags(flags);
++ return 0;
++}
++
++static void
++usb_xmit_timeout(struct net_device *dev )
++{
++ pxa_usb_send_reset();
++ dev->trans_start = jiffies;
++ netif_wake_queue(dev);
++}
++
++
++static int
++usb_eth_open(struct net_device *dev)
++{
++ int rc;
++ rc = pxa_usb_open( "usb-eth" );
++ if ( rc == 0 ) {
++ string_desc_t * pstr;
++ desc_t * pd = pxa_usb_get_descriptor_ptr();
++
++ pd->b.ep1.wMaxPacketSize = make_word( usb_rsize );
++ pd->b.ep2.wMaxPacketSize = make_word( usb_wsize );
++ pd->dev.idVendor = ETHERNET_VENDOR_ID;
++ pd->dev.idProduct = ETHERNET_PRODUCT_ID;
++ pstr = pxa_usb_kmalloc_string_descriptor( "PXA USB NIC" );
++ if ( pstr ) {
++ pxa_usb_set_string_descriptor( 1, pstr );
++ pd->dev.iProduct = 1;
++ }
++ rc = pxa_usb_start();
++ }
++
++ if( rc == 0)
++ {
++ terminating = 0;
++ cur_tx_skb = next_tx_skb = NULL;
++ cur_rx_skb = usb_new_recv_skb();
++ next_rx_skb = usb_new_recv_skb();
++ if (!cur_rx_skb || !next_rx_skb) {
++ printk("%s: can't allocate new skb\n", __FUNCTION__);
++ if (cur_rx_skb)
++ kfree_skb(cur_rx_skb);
++ if (next_rx_skb)
++ kfree_skb(next_rx_skb);
++
++ pxa_usb_stop();
++ pxa_usb_close();
++ return -ENOMEM;;
++ }
++
++ MOD_INC_USE_COUNT;
++#ifndef DMA_NO_COPY
++ pxa_usb_recv(dmabuf, usb_rsize, usb_recv_callback);
++#else
++ pxa_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)),
++ usb_recv_callback);
++#endif
++ }
++
++ return rc;
++}
++
++static int
++usb_eth_release(struct net_device *dev)
++{
++ string_desc_t * pstr;
++
++ terminating = 1;
++ pxa_usb_send_reset();
++ pxa_usb_recv_reset();
++ if (cur_tx_skb)
++ kfree_skb(cur_tx_skb);
++ if (next_tx_skb)
++ kfree_skb(next_tx_skb);
++ if (cur_rx_skb)
++ kfree_skb(cur_rx_skb);
++ if (next_rx_skb)
++ kfree_skb(next_rx_skb);
++
++ pxa_usb_stop();
++ pxa_usb_close();
++ if ( (pstr = pxa_usb_get_string_descriptor(1)) != NULL )
++ kfree( pstr );
++
++ MOD_DEC_USE_COUNT;
++ return 0;
++}
++
++static struct net_device_stats *
++usb_eth_stats(struct net_device *dev)
++{
++ struct usbe_info_t *priv = (struct usbe_info_t*) dev->priv;
++ struct net_device_stats *stats=NULL;
++
++ if (priv)
++ stats = &priv->stats;
++ return stats;
++}
++
++static int
++usb_eth_probe(struct net_device *dev)
++{
++ u8 node_id [ETH_ALEN];
++
++ get_random_bytes (node_id, sizeof node_id);
++ node_id [0] &= 0xfe; // clear multicast bit
++
++ /*
++ * Assign the hardware address of the board:
++ * generate it randomly, as there can be many such
++ * devices on the bus.
++ */
++ memcpy (dev->dev_addr, node_id, sizeof node_id);
++
++ dev->open = usb_eth_open;
++ dev->change_mtu = usb_change_mtu;
++ dev->stop = usb_eth_release;
++ dev->hard_start_xmit = usb_eth_xmit;
++ dev->get_stats = usb_eth_stats;
++ dev->watchdog_timeo = 1*HZ;
++ dev->tx_timeout = usb_xmit_timeout;
++ dev->priv = &usbe_info;
++
++ usbe_info.dev = dev;
++
++ /* clear the statistics */
++ memset(&usbe_info.stats, 0, sizeof(struct net_device_stats));
++
++ ether_setup(dev);
++ dev->flags &= ~IFF_MULTICAST;
++ dev->flags &= ~IFF_BROADCAST;
++ //dev->flags |= IFF_NOARP;
++
++ return 0;
++}
++
++#ifdef MODULE
++MODULE_PARM(usb_rsize, "1i");
++MODULE_PARM_DESC(usb_rsize, "number of bytes in packets from host to pxa");
++MODULE_PARM(usb_wsize, "1i");
++MODULE_PARM_DESC(usb_wsize, "number of bytes in packets from pxa to host");
++#endif
++
++static int __init
++usb_eth_init(void)
++{
++#ifndef DMA_NO_COPY
++ dmabuf = kmalloc( usb_rsize, GFP_KERNEL | GFP_DMA );
++ if (!dmabuf)
++ return -ENOMEM;
++#endif
++ strncpy(usb_eth_device.name, usb_eth_name, IFNAMSIZ);
++ usb_eth_device.init = usb_eth_probe;
++ if (register_netdev(&usb_eth_device) != 0)
++ return -EIO;
++
++ printk( KERN_INFO "USB Function Ethernet Driver Interface\n");
++
++ return 0;
++}
++
++static void __exit
++usb_eth_cleanup(void)
++{
++#ifndef DMA_NO_COPY
++ kfree(dmabuf);
++#endif
++ unregister_netdev(&usb_eth_device);
++}
++
++module_init(usb_eth_init);
++module_exit(usb_eth_cleanup);
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/usb_ctl.c
+@@ -0,0 +1,769 @@
++/*
++ * Copyright (C) Compaq Computer Corporation, 1998, 1999
++ * Copyright (C) Extenex Corporation, 2001
++ * Copyright (C) Intrinsyc, Inc., 2002
++ *
++ * PXA USB controller core driver.
++ *
++ * This file provides interrupt routing and overall coordination
++ * of the endpoints.
++ *
++ * Please see:
++ * linux/Documentation/arm/SA1100/SA1100_USB
++ * for more info.
++ *
++ * 02-May-2002
++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.c
++ *
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/proc_fs.h>
++#include <linux/tqueue.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++
++#include "pxa_usb.h"
++#include "usb_ctl.h"
++
++//#define DEBUG 1
++
++#if DEBUG
++static unsigned int usb_debug = DEBUG;
++#else
++#define usb_debug 0 /* gcc will remove all the debug code for us */
++#endif
++
++//////////////////////////////////////////////////////////////////////////////
++// Prototypes
++//////////////////////////////////////////////////////////////////////////////
++
++int usbctl_next_state_on_event( int event );
++static void udc_int_hndlr(int, void *, struct pt_regs *);
++static void initialize_descriptors( void );
++static void soft_connect_hook( int enable );
++static void udc_disable(void);
++static void udc_enable(void);
++
++#if CONFIG_PROC_FS
++#define PROC_NODE_NAME "driver/pxausb"
++static int usbctl_read_proc(char *page, char **start, off_t off,
++ int count, int *eof, void *data);
++#endif
++
++//////////////////////////////////////////////////////////////////////////////
++// Globals
++//////////////////////////////////////////////////////////////////////////////
++static const char pszMe[] = "usbctl: ";
++struct usb_info_t usbd_info; /* global to ep0, usb_recv, usb_send */
++
++/* device descriptors */
++static desc_t desc;
++
++#define MAX_STRING_DESC 8
++static string_desc_t * string_desc_array[ MAX_STRING_DESC ];
++static string_desc_t sd_zero; /* special sd_zero holds language codes */
++
++// called when configured
++static usb_notify_t configured_callback = NULL;
++
++enum {
++ kStateZombie = 0,
++ kStateZombieSuspend = 1,
++ kStateDefault = 2,
++ kStateDefaultSuspend = 3,
++ kStateAddr = 4,
++ kStateAddrSuspend = 5,
++ kStateConfig = 6,
++ kStateConfigSuspend = 7
++};
++
++/*
++ * FIXME: The PXA UDC handles several host device requests without user
++ * notification/intervention. The table could be collapsed quite a bit...
++ */
++static int device_state_machine[8][6] = {
++// suspend reset resume adddr config deconfig
++/* zombie */ { kStateZombieSuspend , kStateDefault, kStateZombie , kError , kError , kError },
++/* zom sus */ { kStateZombieSuspend , kStateDefault, kStateZombie , kError , kError , kError },
++/* default */ { kStateDefaultSuspend, kStateDefault, kStateDefault, kStateAddr, kStateConfig, kError },
++/* def sus */ { kStateDefaultSuspend, kStateDefault, kStateDefault, kError , kError , kError },
++/* addr */ { kStateAddrSuspend , kStateDefault, kStateAddr , kError , kStateConfig, kError },
++/* addr sus */{ kStateAddrSuspend , kStateDefault, kStateAddr , kError , kError , kError },
++/* config */ { kStateConfigSuspend , kStateDefault, kStateConfig , kError , kError , kStateDefault },
++/* cfg sus */ { kStateConfigSuspend , kStateDefault, kStateConfig , kError , kError , kError }
++};
++
++/* "device state" is the usb device framework state, as opposed to the
++ "state machine state" which is whatever the driver needs and is much
++ more fine grained
++*/
++static int sm_state_to_device_state[8] = {
++// zombie zom suspend
++USB_STATE_POWERED, USB_STATE_SUSPENDED,
++// default default sus
++USB_STATE_DEFAULT, USB_STATE_SUSPENDED,
++// addr addr sus
++USB_STATE_ADDRESS, USB_STATE_SUSPENDED,
++// config config sus
++USB_STATE_CONFIGURED, USB_STATE_SUSPENDED
++};
++
++static char * state_names[8] =
++{ "zombie", "zombie suspended",
++ "default", "default suspended",
++ "address", "address suspended",
++ "configured", "config suspended"
++};
++
++static char * event_names[6] =
++{ "suspend", "reset", "resume",
++ "address assigned", "configure", "de-configure"
++};
++
++static char * device_state_names[] =
++{ "not attached", "attached", "powered", "default",
++ "address", "configured", "suspended" };
++
++static int sm_state = kStateZombie;
++
++//////////////////////////////////////////////////////////////////////////////
++// Async
++//////////////////////////////////////////////////////////////////////////////
++
++/* The UDCCR reg contains mask and interrupt status bits,
++ * so using '|=' isn't safe as it may ack an interrupt.
++ */
++
++void udc_set_mask_UDCCR( int mask )
++{
++ UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS);
++}
++
++void udc_clear_mask_UDCCR( int mask)
++{
++ UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS);
++}
++
++void udc_ack_int_UDCCR( int mask)
++{
++ /* udccr contains the bits we dont want to change */
++ __u32 udccr = UDCCR & UDCCR_MASK_BITS;
++
++ UDCCR = udccr | (mask & ~UDCCR_MASK_BITS);
++}
++
++static void
++udc_int_hndlr(int irq, void *dev_id, struct pt_regs *regs)
++{
++ __u32 status = UDCCR;
++ __u32 ir0_status = USIR0;
++ __u32 ir1_status = USIR1;
++ __u32 uicr0 = UICR0;
++ __u32 uicr1 = UICR1;
++
++ //mask ints
++ udc_set_mask_UDCCR( UDCCR_REM | UDCCR_SRM);
++ UICR0 = 0xff;
++ UICR1 = 0xff;
++
++ if( usb_debug > 2)
++ {
++ printk("%s--- udc_int_hndlr\n"
++ "UDCCR=0x%08x UDCCS0=0x%08x UDCCS1=0x%08x UDCCS2=0x%08x\n"
++ "USIR0=0x%08x USIR1=0x%08x UICR0=0x%08x UICR1=0x%08x\n",
++ pszMe, status, UDCCS0, UDCCS1, UDCCS2, ir0_status, ir1_status, uicr0, uicr1);
++ }
++
++ /* SUSpend Interrupt Request */
++ if ( status & UDCCR_SUSIR )
++ {
++ udc_ack_int_UDCCR( UDCCR_SUSIR);
++ if( usb_debug) printk("%sSuspend...\n", pszMe);
++ usbctl_next_state_on_event( kEvSuspend );
++ }
++
++ /* RESume Interrupt Request */
++ if ( status & UDCCR_RESIR )
++ {
++ udc_ack_int_UDCCR( UDCCR_RESIR);
++ if( usb_debug) printk("%sResume...\n", pszMe);
++ usbctl_next_state_on_event( kEvResume );
++ }
++
++ /* ReSeT Interrupt Request - UDC has been reset */
++ if ( status & UDCCR_RSTIR )
++ {
++ /* clear the reset interrupt */
++ udc_ack_int_UDCCR( UDCCR_RSTIR);
++
++ /* check type of reset */
++ if( (UDCCR & UDCCR_UDA) == 0)
++ {
++ /* reset assertion took place, nothing to do */
++ if( usb_debug) printk("%sReset assertion...\n", pszMe);
++ }
++
++ /* ok, it's a reset negation, go on with reset */
++ else if ( usbctl_next_state_on_event( kEvReset ) != kError )
++ {
++ /* starting reset sequence now... */
++ if( usb_debug) printk("%sResetting\n", pszMe);
++
++ ep0_reset();
++ ep_bulk_in1_reset();
++ ep_bulk_out1_reset();
++
++ usbctl_next_state_on_event( kEvConfig );
++ }
++ else
++ {
++ printk("%sUnexpected reset\n", pszMe);
++ }
++ }
++ else
++ {
++ /* ep0 int */
++ if (ir0_status & USIR0_IR0)
++ ep0_int_hndlr();
++
++ /* transmit bulk */
++ if (ir0_status & USIR0_IR1)
++ ep_bulk_in1_int_hndlr(ir0_status);
++
++ /* receive bulk */
++ if ( ir0_status & USIR0_IR2)
++ ep_bulk_out1_int_hndlr(ir0_status);
++
++ while (UDCCS2 & UDCCS_BO_RNE)
++ {
++ if( usb_debug) printk("More Bulk-out data...\n");
++ ep_bulk_out1_int_hndlr(ir0_status);
++ }
++ }
++
++ UICR0 = uicr0;
++ UICR1 = uicr1;
++ udc_clear_mask_UDCCR( UDCCR_SRM | UDCCR_REM); /* enable suspend/resume, reset */
++
++ /* clear all endpoint ints */
++ USIR0 |= 0xff;
++ USIR1 |= 0xff;
++
++ if( usb_debug > 2)
++ {
++ printk("%sudc_int_hndlr\n"
++ "UDCCR=0x%08x UDCCS0=0x%08x UDCCS1=0x%08x UDCCS2=0x%08x\n"
++ "USIR0=0x%08x USIR1=0x%08x UICR0=0x%08x UICR1=0x%08x\n",
++ pszMe, UDCCR, UDCCS0, UDCCS1, UDCCS2, USIR0, USIR1, UICR0, UICR1);
++ }
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// Public Interface
++//////////////////////////////////////////////////////////////////////////////
++
++/* Open PXA usb core on behalf of a client, but don't start running */
++
++int
++pxa_usb_open( const char * client )
++{
++ if ( usbd_info.client_name != NULL )
++ {
++ printk( "%sUnable to register %s (%s already registered).\n",
++ pszMe, client, usbd_info.client_name );
++ return -EBUSY;
++ }
++
++ usbd_info.client_name = (char*) client;
++ memset(&usbd_info.stats, 0, sizeof(struct usb_stats_t));
++ memset(string_desc_array, 0, sizeof(string_desc_array));
++
++ /* hack to start in zombie suspended state */
++ sm_state = kStateZombieSuspend;
++ usbd_info.state = USB_STATE_SUSPENDED;
++
++ /* create descriptors for enumeration */
++ initialize_descriptors();
++
++ printk( "%s%s registered.\n", pszMe, client );
++ return 0;
++}
++
++/* Start running. Must have called usb_open (above) first */
++int
++pxa_usb_start( void )
++{
++ if ( usbd_info.client_name == NULL ) {
++ printk( "%s%s - no client registered\n",
++ pszMe, __FUNCTION__ );
++ return -EPERM;
++ }
++
++ /* start UDC internal machinery running */
++ udc_enable();
++ udelay( 100 );
++
++ /* flush DMA and fire through some -EAGAINs */
++ ep_bulk_out1_init( usbd_info.dmach_rx );
++ ep_bulk_in1_init( usbd_info.dmach_tx );
++
++ /* give endpoint notification we are starting */
++ ep_bulk_out1_state_change_notify( USB_STATE_SUSPENDED );
++ ep_bulk_in1_state_change_notify( USB_STATE_SUSPENDED );
++
++ /* enable any platform specific hardware */
++ soft_connect_hook( 1 );
++
++ /* enable suspend/resume, reset */
++ udc_clear_mask_UDCCR( UDCCR_SRM | UDCCR_REM);
++ /* enable ep0, ep1, ep2 */
++ UICR0 &= ~(UICR0_IM0 | UICR0_IM1 | UICR0_IM2);
++
++ if( usb_debug) printk( "%sStarted %s\n", pszMe, usbd_info.client_name );
++ return 0;
++}
++
++/* Stop USB core from running */
++int
++pxa_usb_stop( void )
++{
++ if ( usbd_info.client_name == NULL ) {
++ printk( "%s%s - no client registered\n",
++ pszMe, __FUNCTION__ );
++ return -EPERM;
++ }
++ /* mask everything */
++ /* disable suspend/resume, reset */
++ udc_set_mask_UDCCR( UDCCR_SRM | UDCCR_REM);
++ /* disable ep0, ep1, ep2 */
++ UICR0 |= (UICR0_IM0 | UICR0_IM1 | UICR0_IM2);
++
++ ep_bulk_out1_reset();
++ ep_bulk_in1_reset();
++
++ udc_disable();
++ if( usb_debug) printk( "%sStopped %s\n", pszMe, usbd_info.client_name );
++ return 0;
++}
++
++/* Tell PXA core client is through using it */
++int
++pxa_usb_close( void )
++{
++ if ( usbd_info.client_name == NULL ) {
++ printk( "%s%s - no client registered\n",
++ pszMe, __FUNCTION__ );
++ return -EPERM;
++ }
++ printk( "%s%s closed.\n", pszMe, (char*)usbd_info.client_name );
++ usbd_info.client_name = NULL;
++ return 0;
++}
++
++/* set a proc to be called when device is configured */
++usb_notify_t pxa_set_configured_callback( usb_notify_t func )
++{
++ usb_notify_t retval = configured_callback;
++ configured_callback = func;
++ return retval;
++}
++
++/*====================================================
++ * Descriptor Manipulation.
++ * Use these between open() and start() above to setup
++ * the descriptors for your device.
++ *
++ */
++
++/* get pointer to static default descriptor */
++desc_t *
++pxa_usb_get_descriptor_ptr( void ) { return &desc; }
++
++/* optional: set a string descriptor */
++int
++pxa_usb_set_string_descriptor( int i, string_desc_t * p )
++{
++ int retval;
++ if ( i < MAX_STRING_DESC ) {
++ string_desc_array[i] = p;
++ retval = 0;
++ } else {
++ retval = -EINVAL;
++ }
++ return retval;
++}
++
++/* optional: get a previously set string descriptor */
++string_desc_t *
++pxa_usb_get_string_descriptor( int i )
++{
++ return ( i < MAX_STRING_DESC )
++ ? string_desc_array[i]
++ : NULL;
++}
++
++
++/* optional: kmalloc and unicode up a string descriptor */
++string_desc_t *
++pxa_usb_kmalloc_string_descriptor( const char * p )
++{
++ string_desc_t * pResult = NULL;
++
++ if ( p ) {
++ int len = strlen( p );
++ int uni_len = len * sizeof( __u16 );
++ pResult = (string_desc_t*) kmalloc( uni_len + 2, GFP_KERNEL ); /* ugh! */
++ if ( pResult != NULL ) {
++ int i;
++ pResult->bLength = uni_len + 2;
++ pResult->bDescriptorType = USB_DESC_STRING;
++ for( i = 0; i < len ; i++ ) {
++ pResult->bString[i] = make_word( (__u16) p[i] );
++ }
++ }
++ }
++ return pResult;
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// Exports to rest of driver
++//////////////////////////////////////////////////////////////////////////////
++
++/* called by the int handler here and the two endpoint files when interesting
++ .."events" happen */
++
++int
++usbctl_next_state_on_event( int event )
++{
++ int next_state = device_state_machine[ sm_state ][ event ];
++ if ( next_state != kError )
++ {
++ int next_device_state = sm_state_to_device_state[ next_state ];
++ if( usb_debug) printk( "%s%s --> [%s] --> %s. Device in %s state.\n",
++ pszMe, state_names[ sm_state ], event_names[ event ],
++ state_names[ next_state ], device_state_names[ next_device_state ] );
++
++ sm_state = next_state;
++ if ( usbd_info.state != next_device_state )
++ {
++ if ( configured_callback != NULL
++ &&
++ next_device_state == USB_STATE_CONFIGURED
++ &&
++ usbd_info.state != USB_STATE_SUSPENDED
++ ) {
++ configured_callback();
++ }
++ usbd_info.state = next_device_state;
++
++ ep_bulk_out1_state_change_notify( next_device_state );
++ ep_bulk_in1_state_change_notify( next_device_state );
++ }
++ }
++#if 1
++ else
++ printk( "%s%s --> [%s] --> ??? is an error.\n",
++ pszMe, state_names[ sm_state ], event_names[ event ] );
++#endif
++ return next_state;
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// Private Helpers
++//////////////////////////////////////////////////////////////////////////////
++
++/* setup default descriptors */
++
++static void
++initialize_descriptors(void)
++{
++ desc.dev.bLength = sizeof( device_desc_t );
++ desc.dev.bDescriptorType = USB_DESC_DEVICE;
++ desc.dev.bcdUSB = 0x100; /* 1.0 */
++ desc.dev.bDeviceClass = 0xFF; /* vendor specific */
++ desc.dev.bDeviceSubClass = 0;
++ desc.dev.bDeviceProtocol = 0;
++ desc.dev.bMaxPacketSize0 = 16; /* ep0 max fifo size */
++ desc.dev.idVendor = 0; /* vendor ID undefined */
++ desc.dev.idProduct = 0; /* product */
++ desc.dev.bcdDevice = 0; /* vendor assigned device release num */
++ desc.dev.iManufacturer = 0; /* index of manufacturer string */
++ desc.dev.iProduct = 0; /* index of product description string */
++ desc.dev.iSerialNumber = 0; /* index of string holding product s/n */
++ desc.dev.bNumConfigurations = 1;
++
++ desc.b.cfg.bLength = sizeof( config_desc_t );
++ desc.b.cfg.bDescriptorType = USB_DESC_CONFIG;
++ desc.b.cfg.wTotalLength = make_word_c( sizeof(struct cdb) );
++ desc.b.cfg.bNumInterfaces = 1;
++ desc.b.cfg.bConfigurationValue = 1;
++ desc.b.cfg.iConfiguration = 0;
++ desc.b.cfg.bmAttributes = USB_CONFIG_BUSPOWERED;
++ desc.b.cfg.MaxPower = USB_POWER( 500 );
++
++ desc.b.intf.bLength = sizeof( intf_desc_t );
++ desc.b.intf.bDescriptorType = USB_DESC_INTERFACE;
++ desc.b.intf.bInterfaceNumber = 0; /* unique intf index*/
++ desc.b.intf.bAlternateSetting = 0;
++ desc.b.intf.bNumEndpoints = 2;
++ desc.b.intf.bInterfaceClass = 0xFF; /* vendor specific */
++ desc.b.intf.bInterfaceSubClass = 0;
++ desc.b.intf.bInterfaceProtocol = 0;
++ desc.b.intf.iInterface = 0;
++
++/*
++ * FIXME...
++ * The host usbnet driver expects EP1=out EP2=in. On the PXA UDC EP1=in, EP2=out
++ */
++ desc.b.ep1.bLength = sizeof( ep_desc_t );
++ desc.b.ep1.bDescriptorType = USB_DESC_ENDPOINT;
++ desc.b.ep1.bEndpointAddress = USB_EP_ADDRESS( 1, USB_IN );
++ desc.b.ep1.bmAttributes = USB_EP_BULK;
++ desc.b.ep1.wMaxPacketSize = make_word_c( 64 );
++ desc.b.ep1.bInterval = 0;
++
++ desc.b.ep2.bLength = sizeof( ep_desc_t );
++ desc.b.ep2.bDescriptorType = USB_DESC_ENDPOINT;
++ desc.b.ep2.bEndpointAddress = USB_EP_ADDRESS( 2, USB_OUT );
++ desc.b.ep2.bmAttributes = USB_EP_BULK;
++ desc.b.ep2.wMaxPacketSize = make_word_c( 64 );
++ desc.b.ep2.bInterval = 0;
++
++// FIXME: Add support for all endpoint...
++
++ /* set language */
++ /* See: http://www.usb.org/developers/data/USB_LANGIDs.pdf */
++ sd_zero.bDescriptorType = USB_DESC_STRING;
++ sd_zero.bLength = sizeof( string_desc_t );
++ sd_zero.bString[0] = make_word_c( 0x409 ); /* American English */
++ pxa_usb_set_string_descriptor( 0, &sd_zero );
++}
++
++/* soft_connect_hook()
++ * Some devices have platform-specific circuitry to make USB
++ * not seem to be plugged in, even when it is. This allows
++ * software to control when a device 'appears' on the USB bus
++ * (after Linux has booted and this driver has loaded, for
++ * example). If you have such a circuit, control it here.
++ */
++static void
++soft_connect_hook( int enable )
++{
++}
++
++/* disable the UDC at the source */
++static void
++udc_disable(void)
++{
++ soft_connect_hook( 0 );
++ /* clear UDC-enable */
++ udc_clear_mask_UDCCR( UDCCR_UDE);
++
++ /* Disable clock for USB device */
++ CKEN &= ~CKEN11_USB;
++}
++
++
++/* enable the udc at the source */
++static void
++udc_enable(void)
++{
++ /* Enable clock for USB device */
++ CKEN |= CKEN11_USB;
++
++ /* try to clear these bits before we enable the udc */
++ udc_ack_int_UDCCR( UDCCR_SUSIR);
++ udc_ack_int_UDCCR( UDCCR_RSTIR);
++ udc_ack_int_UDCCR( UDCCR_RESIR);
++
++ /* set UDC-enable */
++ udc_set_mask_UDCCR( UDCCR_UDE);
++ if( (UDCCR & UDCCR_UDA) == 0)
++ {
++ /* There's a reset on the bus,
++ * clear the interrupt bit and keep going
++ */
++ udc_ack_int_UDCCR( UDCCR_RSTIR);
++ }
++
++ /* "USB test mode" to work around errata 40-42 (stepping a0, a1)
++ * which could result in missing packets and interrupts.
++ * Supposedly this turns off double buffering for all endpoints.
++ */
++ if( usb_debug) printk( "USB RES1=%x RES2=%x RES3=%x\n", UDC_RES1, UDC_RES2, UDC_RES3);
++ UDC_RES1 = 0x00;
++ UDC_RES2 = 0x00;
++ if( usb_debug) printk( "USB RES1=%x RES2=%x RES3=%x\n", UDC_RES1, UDC_RES2, UDC_RES3);
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// Proc Filesystem Support
++//////////////////////////////////////////////////////////////////////////////
++
++#if CONFIG_PROC_FS
++
++#define SAY( fmt, args... ) p += sprintf(p, fmt, ## args )
++#define SAYV( num ) p += sprintf(p, num_fmt, "Value", num )
++#define SAYC( label, yn ) p += sprintf(p, yn_fmt, label, yn )
++#define SAYS( label, v ) p += sprintf(p, cnt_fmt, label, v )
++
++static int usbctl_read_proc(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ const char * num_fmt = "%25.25s: %8.8lX\n";
++ const char * cnt_fmt = "%25.25s: %lu\n";
++ const char * yn_fmt = "%25.25s: %s\n";
++ const char * yes = "YES";
++ const char * no = "NO";
++ unsigned long v;
++ char * p = page;
++ int len;
++
++ SAY( "PXA USB Controller Core\n" );
++ SAY( "Active Client: %s\n", usbd_info.client_name ? usbd_info.client_name : "none");
++ SAY( "USB state: %s (%s) %d\n",
++ device_state_names[ sm_state_to_device_state[ sm_state ] ],
++ state_names[ sm_state ],
++ sm_state );
++
++ SAYS( "ep0 bytes read", usbd_info.stats.ep0_bytes_read );
++ SAYS( "ep0 bytes written", usbd_info.stats.ep0_bytes_written );
++ SAYS( "ep0 FIFO read failures", usbd_info.stats.ep0_fifo_write_failures );
++ SAYS( "ep0 FIFO write failures", usbd_info.stats.ep0_fifo_write_failures );
++
++ SAY( "\n" );
++
++ v = UDCCR;
++ SAY( "\nUDC Control Register\n" );
++ SAYV( v );
++ SAYC( "UDC Enabled", ( v & UDCCR_UDE ) ? yes : no );
++ SAYC( "UDC Active", ( v & UDCCR_UDA ) ? yes : no );
++ SAYC( "Suspend/Resume interrupts masked", ( v & UDCCR_SRM ) ? yes : no );
++ SAYC( "Reset interrupts masked", ( v & UDCCR_REM ) ? yes : no );
++ SAYC( "Reset pending", ( v & UDCCR_RSTIR ) ? yes : no );
++ SAYC( "Suspend pending", ( v & UDCCR_SUSIR ) ? yes : no );
++ SAYC( "Resume pending", ( v & UDCCR_RESIR ) ? yes : no );
++
++ len = ( p - page ) - off;
++ if ( len < 0 )
++ len = 0;
++ *eof = ( len <=count ) ? 1 : 0;
++ *start = page + off;
++ return len;
++}
++
++#endif /* CONFIG_PROC_FS */
++
++#if 0
++static void irq_handler(int channel, void *data, struct pt_regs *regs)
++{
++ if( channel == usbd_info.dmach_rx)
++ {
++ printk( "USB receive DMA\n");
++ }
++ else if( channel == usbd_info.dmach_tx)
++ {
++ printk( "USB transmit DMA\n");
++ }
++ else
++ {
++ printk( "USB unknown DMA channel\n");
++ }
++}
++#endif
++
++//////////////////////////////////////////////////////////////////////////////
++// Module Initialization and Shutdown
++//////////////////////////////////////////////////////////////////////////////
++/*
++ * usbctl_init()
++ * Module load time. Allocate dma and interrupt resources. Setup /proc fs
++ * entry. Leave UDC disabled.
++ */
++int __init usbctl_init( void )
++{
++ int retval = 0;
++
++ udc_disable();
++
++ memset( &usbd_info, 0, sizeof( usbd_info ) );
++
++#if CONFIG_PROC_FS
++ create_proc_read_entry ( PROC_NODE_NAME, 0, NULL, usbctl_read_proc, NULL);
++#endif
++
++#if 0
++ /* setup rx dma */
++ usbd_info.dmach_rx = pxa_request_dma("USB receive", DMA_PRIO_MEDIUM, irq_handler, 0 /*data; DMA_Ser0UDCRd*/);
++ if (usbd_info.dmach_rx < 0) {
++ printk("%sunable to register for rx dma rc=%d\n", pszMe, usbd_info.dmach_rx );
++ goto err_rx_dma;
++ }
++
++ /* setup tx dma */
++ usbd_info.dmach_tx = pxa_request_dma("USB receive", DMA_PRIO_MEDIUM, irq_handler, 0 /*data; DMA_Ser0UDCRd*/);
++ if (usbd_info.dmach_tx < 0) {
++ printk("%sunable to register for tx dma rc=%d\n",pszMe,usbd_info.dmach_tx);
++ goto err_tx_dma;
++ }
++#endif
++
++ /* now allocate the IRQ. */
++ retval = request_irq(IRQ_USB, udc_int_hndlr, SA_INTERRUPT, "PXA USB core", NULL);
++ if (retval) {
++ printk("%sCouldn't request USB irq rc=%d\n",pszMe, retval);
++ goto err_irq;
++ }
++
++ printk( "PXA USB Controller Core Initialized\n");
++ return 0;
++
++err_irq:
++#if 0
++ pxa_free_dma(usbd_info.dmach_tx);
++ usbd_info.dmach_tx = 0;
++err_tx_dma:
++ pxa_free_dma(usbd_info.dmach_rx);
++ usbd_info.dmach_rx = 0;
++err_rx_dma:
++#endif
++ return retval;
++}
++/*
++ * usbctl_exit()
++ * Release DMA and interrupt resources
++ */
++void __exit usbctl_exit( void )
++{
++ printk("Unloading PXA USB Controller\n");
++
++ udc_disable();
++
++#if CONFIG_PROC_FS
++ remove_proc_entry ( PROC_NODE_NAME, NULL);
++#endif
++
++ pxa_free_dma(usbd_info.dmach_rx);
++ pxa_free_dma(usbd_info.dmach_tx);
++ free_irq(IRQ_USB, NULL);
++}
++
++module_init( usbctl_init );
++module_exit( usbctl_exit );
++
++EXPORT_SYMBOL( pxa_usb_open );
++EXPORT_SYMBOL( pxa_usb_start );
++EXPORT_SYMBOL( pxa_usb_stop );
++EXPORT_SYMBOL( pxa_usb_close );
++EXPORT_SYMBOL( pxa_usb_get_descriptor_ptr );
++EXPORT_SYMBOL( pxa_usb_set_string_descriptor );
++EXPORT_SYMBOL( pxa_usb_get_string_descriptor );
++EXPORT_SYMBOL( pxa_usb_kmalloc_string_descriptor );
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/usb_ctl.h
+@@ -0,0 +1,89 @@
++/*
++ * Copyright (C) Compaq Computer Corporation, 1998, 1999
++ * Copyright (C) Extenex Corporation 2001
++ * Copyright (C) Intrinsyc, Inc., 2002
++ *
++ * usb_ctl.h
++ *
++ * PRIVATE interface used to share info among components of the PXA USB
++ * core: usb_ctl, usb_ep0, usb_recv and usb_send. Clients of the USB core
++ * should use pxa_usb.h.
++ *
++ * 02-May-2002
++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.h
++ *
++ */
++
++#ifndef _USB_CTL_H
++#define _USB_CTL_H
++
++/* Interrupt mask bits and UDC enable bit */
++#define UDCCR_MASK_BITS (UDCCR_REM | UDCCR_SRM | UDCCR_UDE)
++
++/*
++ * These states correspond to those in the USB specification v1.0
++ * in chapter 8, Device Framework.
++ */
++enum {
++ USB_STATE_NOTATTACHED =0,
++ USB_STATE_ATTACHED =1,
++ USB_STATE_POWERED =2,
++ USB_STATE_DEFAULT =3,
++ USB_STATE_ADDRESS =4,
++ USB_STATE_CONFIGURED =5,
++ USB_STATE_SUSPENDED =6
++};
++
++struct usb_stats_t {
++ unsigned long ep0_fifo_write_failures;
++ unsigned long ep0_bytes_written;
++ unsigned long ep0_fifo_read_failures;
++ unsigned long ep0_bytes_read;
++};
++
++struct usb_info_t
++{
++ char * client_name;
++ dmach_t dmach_tx, dmach_rx;
++ int state;
++ unsigned char address;
++ struct usb_stats_t stats;
++};
++
++/* in usb_ctl.c */
++extern struct usb_info_t usbd_info;
++
++/*
++ * Function Prototypes
++ */
++enum {
++ kError =-1,
++ kEvSuspend =0,
++ kEvReset =1,
++ kEvResume =2,
++ kEvAddress =3,
++ kEvConfig =4,
++ kEvDeConfig =5
++};
++int usbctl_next_state_on_event( int event );
++
++/* endpoint zero */
++void ep0_reset(void);
++void ep0_int_hndlr(void);
++
++/* receiver */
++void ep_bulk_out1_state_change_notify( int new_state );
++int ep_bulk_out1_recv(void);
++int ep_bulk_out1_init(int chn);
++void ep_bulk_out1_int_hndlr(int status);
++void ep_bulk_out1_reset(void);
++void ep_bulk_out1_stall(void);
++
++/* xmitter */
++void ep_bulk_in1_state_change_notify( int new_state );
++void ep_bulk_in1_reset(void);
++int ep_bulk_in1_init(int chn);
++void ep_bulk_in1_int_hndlr(int status);
++void ep_bulk_in1_stall(void);
++
++#endif /* _USB_CTL_H */
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/usb_ep0.c
+@@ -0,0 +1,556 @@
++/*
++ * Copyright (C) Extenex Corporation 2001
++ * Copyright (C) Compaq Computer Corporation, 1998, 1999
++ * Copyright (C) Intrinsyc, Inc., 2002
++ *
++ * PXA USB controller driver - Endpoint zero management
++ *
++ * Please see:
++ * linux/Documentation/arm/SA1100/SA1100_USB
++ * for more info.
++ *
++ * 02-May-2002
++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.c
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/tqueue.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++#include <asm/irq.h>
++
++#include "pxa_usb.h" /* public interface */
++#include "usb_ctl.h" /* private stuff */
++#include "usb_ep0.h"
++
++
++// 1 == lots of trace noise, 0 = only "important' stuff
++#define VERBOSITY 0
++
++enum { true = 1, false = 0 };
++typedef int bool;
++#ifndef MIN
++#define MIN( a, b ) ((a)<(b)?(a):(b))
++#endif
++
++#if 1 && !defined( ASSERT )
++# define ASSERT(expr) \
++if(!(expr)) { \
++ printk( "Assertion failed! %s,%s,%s,line=%d\n",\
++#expr,__FILE__,__FUNCTION__,__LINE__); \
++}
++#else
++# define ASSERT(expr)
++#endif
++
++#if VERBOSITY
++#define PRINTKD(fmt, args...) printk( fmt , ## args)
++#else
++#define PRINTKD(fmt, args...)
++#endif
++
++static EP0_state ep0_state = EP0_IDLE;
++
++/***************************************************************************
++ Prototypes
++ ***************************************************************************/
++/* "setup handlers" -- the main functions dispatched to by the
++ .. isr. These represent the major "modes" of endpoint 0 operation */
++static void sh_setup_begin(void); /* setup begin (idle) */
++static void sh_write( void ); /* writing data */
++static int read_fifo( usb_dev_request_t * p );
++static void write_fifo( void );
++static void get_descriptor( usb_dev_request_t * pReq );
++static void queue_and_start_write( void * p, int req, int act );
++
++/***************************************************************************
++ Inline Helpers
++ ***************************************************************************/
++
++inline int type_code_from_request( __u8 by ) { return (( by >> 4 ) & 3); }
++
++/* print string descriptor */
++static inline void psdesc( string_desc_t * p )
++{
++ int i;
++ int nchars = ( p->bLength - 2 ) / sizeof( __u16 );
++ printk( "'" );
++ for( i = 0 ; i < nchars ; i++ ) {
++ printk( "%c", (char) p->bString[i] );
++ }
++ printk( "'\n" );
++}
++
++#if VERBOSITY
++/* "pcs" == "print control status" */
++static inline void pcs( void )
++{
++ __u32 foo = UDCCS0;
++ printk( "%08x: %s %s %s %s %s %s\n",
++ foo,
++ foo & UDCCS0_SA ? "SA" : "",
++ foo & UDCCS0_OPR ? "OPR" : "",
++ foo & UDCCS0_RNE ? "RNE" : "",
++ foo & UDCCS0_SST ? "SST" : "",
++ foo & UDCCS0_FST ? "FST" : "",
++ foo & UDCCS0_DRWF ? "DRWF" : ""
++ );
++}
++static inline void preq( usb_dev_request_t * pReq )
++{
++ static char * tnames[] = { "dev", "intf", "ep", "oth" };
++ static char * rnames[] = { "std", "class", "vendor", "???" };
++ char * psz;
++ switch( pReq->bRequest ) {
++ case GET_STATUS: psz = "get stat"; break;
++ case CLEAR_FEATURE: psz = "clr feat"; break;
++ case SET_FEATURE: psz = "set feat"; break;
++ case SET_ADDRESS: psz = "set addr"; break;
++ case GET_DESCRIPTOR: psz = "get desc"; break;
++ case SET_DESCRIPTOR: psz = "set desc"; break;
++ case GET_CONFIGURATION: psz = "get cfg"; break;
++ case SET_CONFIGURATION: psz = "set cfg"; break;
++ case GET_INTERFACE: psz = "get intf"; break;
++ case SET_INTERFACE: psz = "set intf"; break;
++ case SYNCH_FRAME: psz = "synch frame"; break;
++ default: psz = "unknown"; break;
++ }
++ printk( "- [%s: %s req to %s. dir=%s]\n", psz,
++ rnames[ (pReq->bmRequestType >> 5) & 3 ],
++ tnames[ pReq->bmRequestType & 3 ],
++ ( pReq->bmRequestType & 0x80 ) ? "in" : "out" );
++}
++
++#else
++static inline void pcs( void ){}
++static inline void preq( usb_dev_request_t *x){}
++#endif
++
++/***************************************************************************
++ Globals
++ ***************************************************************************/
++static const char pszMe[] = "usbep0: ";
++
++/* pointer to current setup handler */
++static void (*current_handler)(void) = sh_setup_begin;
++
++/* global write struct to keep write
++ ..state around across interrupts */
++static struct {
++ unsigned char *p;
++ int bytes_left;
++} wr;
++
++/***************************************************************************
++ Public Interface
++ ***************************************************************************/
++
++/* reset received from HUB (or controller just went nuts and reset by itself!)
++ so udc core has been reset, track this state here */
++void ep0_reset(void)
++{
++ PRINTKD( "%sep0_reset\n", pszMe);
++ /* reset state machine */
++ current_handler = sh_setup_begin;
++ wr.p = NULL;
++ wr.bytes_left = 0;
++ usbd_info.address=0;
++}
++
++/* handle interrupt for endpoint zero */
++void ep0_int_hndlr( void )
++{
++ PRINTKD( "%sep0_int_hndlr\n", pszMe);
++ pcs();
++ (*current_handler)();
++}
++
++/***************************************************************************
++ Setup Handlers
++ ***************************************************************************/
++/*
++ * sh_setup_begin()
++ * This setup handler is the "idle" state of endpoint zero. It looks for OPR
++ * (OUT packet ready) to see if a setup request has been been received from the
++ * host.
++ *
++ */
++static void sh_setup_begin( void )
++{
++ usb_dev_request_t req;
++ int request_type;
++ int n;
++ __u32 cs_reg_in = UDCCS0;
++
++ PRINTKD( "%ssh_setup_begin\n", pszMe);
++
++ /* Be sure out packet ready, otherwise something is wrong */
++ if ( (cs_reg_in & UDCCS0_OPR) == 0 ) {
++ /* we can get here early...if so, we'll int again in a moment */
++ PRINTKD( "%ssetup begin: no OUT packet available. Exiting\n", pszMe );
++ goto sh_sb_end;
++ }
++
++ if( ((cs_reg_in & UDCCS0_SA) == 0) && (ep0_state == EP0_IN_DATA_PHASE))
++ {
++ PRINTKD( "%ssetup begin: premature status\n", pszMe );
++
++ /* premature status, reset tx fifo and go back to idle state*/
++ UDCCS0 = UDCCS0_OPR | UDCCS0_FTF;
++
++ ep0_state = EP0_IDLE;
++ return;
++ }
++
++ if( (UDCCS0 & UDCCS0_RNE) == 0)
++ {
++ /* zero-length OUT? */
++ printk( "%ssetup begin: zero-length OUT?\n", pszMe );
++ goto sh_sb_end;
++ }
++
++ /* read the setup request */
++ n = read_fifo( &req );
++ if ( n != sizeof( req ) ) {
++ printk( "%ssetup begin: fifo READ ERROR wanted %d bytes got %d. "
++ " Stalling out...\n",
++ pszMe, sizeof( req ), n );
++ /* force stall, serviced out */
++ UDCCS0 = UDCCS0_FST;
++ goto sh_sb_end;
++ }
++
++ /* Is it a standard request? (not vendor or class request) */
++ request_type = type_code_from_request( req.bmRequestType );
++ if ( request_type != 0 ) {
++ printk( "%ssetup begin: unsupported bmRequestType: %d ignored\n",
++ pszMe, request_type );
++ goto sh_sb_end;
++ }
++
++#if VERBOSITY
++ {
++ unsigned char * pdb = (unsigned char *) &req;
++ PRINTKD( "%2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X ",
++ pdb[0], pdb[1], pdb[2], pdb[3], pdb[4], pdb[5], pdb[6], pdb[7]
++ );
++ preq( &req );
++ }
++#endif
++
++ /* Handle it */
++ switch( req.bRequest ) {
++
++ case SET_ADDRESS:
++ PRINTKD( "%sSET_ADDRESS handled by UDC\n", pszMe);
++ break;
++#if 0 /* NOT_NEEDED */
++
++ case SET_FEATURE:
++ PRINTKD( "%sSET_FEATURE handled by UDC\n", pszMe);
++ break;
++
++ case CLEAR_FEATURE:
++ PRINTKD( "%sCLEAR_FEATURE handled by UDC\n", pszMe);
++ break;
++
++ case GET_CONFIGURATION:
++ PRINTKD( "%sGET_CONFIGURATION handled by UDC\n", pszMe );
++ break;
++
++ case GET_STATUS:
++ PRINTKD( "%s%sGET_STATUS handled by UDC\n", pszMe );
++ break;
++
++ case GET_INTERFACE:
++ PRINTKD( "%sGET_INTERFACE handled by UDC\n", pszMe);
++ break;
++
++ case SYNCH_FRAME:
++ PRINTKD( "%sSYNCH_FRAME handled by UDC\n", pszMe );
++ break;
++#endif
++
++ case GET_DESCRIPTOR:
++ PRINTKD( "%sGET_DESCRIPTOR\n", pszMe );
++ get_descriptor( &req );
++ break;
++
++ case SET_INTERFACE:
++ PRINTKD( "%sSET_INTERFACE TODO...\n", pszMe);
++ break;
++
++ case SET_DESCRIPTOR:
++ PRINTKD( "%sSET_DESCRIPTOR TODO...\n", pszMe );
++ break;
++
++ case SET_CONFIGURATION:
++ PRINTKD( "%sSET_CONFIGURATION %d\n", pszMe, req.wValue);
++
++/*
++ * FIXME: Something is not quite right here... I only ever get a
++ * de-configure from the host. Ignoring it for now, since usb
++ * ethernet won't do anything unless usb is 'configured'.
++ *
++ */
++#if 0
++ switch( req.wValue)
++ {
++ case 0:
++ /* configured */
++ usbctl_next_state_on_event( kEvConfig );
++ break;
++ case 1:
++ /* de-configured */
++ usbctl_next_state_on_event( kEvDeConfig );
++ break;
++ default:
++ PRINTKD( "%sSET_CONFIGURATION: unknown configuration value (%d)\n", pszMe, req.wValue);
++ break;
++ }
++#endif
++ break;
++ default :
++ printk("%sunknown request 0x%x\n", pszMe, req.bRequest);
++ break;
++ } /* switch( bRequest ) */
++
++sh_sb_end:
++ return;
++}
++
++/*
++ * sh_write()
++ *
++ * Due to UDC bugs we push everything into the fifo in one go.
++ * Using interrupts just didn't work right...
++ * This should be ok, since control request are small.
++ */
++static void sh_write()
++{
++ PRINTKD( "sh_write\n" );
++ do
++ {
++ write_fifo();
++ } while( ep0_state != EP0_END_XFER);
++}
++
++/***************************************************************************
++ Other Private Subroutines
++ ***************************************************************************/
++/*
++ * queue_and_start_write()
++ * data == data to send
++ * req == bytes host requested
++ * act == bytes we actually have
++ *
++ * Sets up the global "wr"-ite structure and load the outbound FIFO
++ * with data.
++ *
++ */
++static void queue_and_start_write( void * data, int req, int act )
++{
++ PRINTKD( "write start: bytes requested=%d actual=%d\n", req, act);
++
++ wr.p = (unsigned char*) data;
++ wr.bytes_left = MIN( act, req );
++
++ ep0_state = EP0_IN_DATA_PHASE;
++ sh_write();
++
++ return;
++}
++/*
++ * write_fifo()
++ * Stick bytes in the endpoint zero FIFO.
++ *
++ */
++static void write_fifo( void )
++{
++ int bytes_this_time = MIN( wr.bytes_left, EP0_FIFO_SIZE );
++ int bytes_written = 0;
++
++ while( bytes_this_time-- ) {
++// PRINTKD( "%2.2X ", *wr.p );
++ UDDR0 = *wr.p++;
++ bytes_written++;
++ }
++ wr.bytes_left -= bytes_written;
++
++ usbd_info.stats.ep0_bytes_written += bytes_written;
++
++ if( (wr.bytes_left==0))
++ {
++ wr.p = NULL; /* be anal */
++
++ if(bytes_written < EP0_FIFO_SIZE)
++ {
++ int count;
++ int udccs0;
++
++ /* We always end the transfer with a short or zero length packet */
++ ep0_state = EP0_END_XFER;
++ current_handler = sh_setup_begin;
++
++ /* Let the packet go... */
++ UDCCS0 = UDCCS0_IPR;
++
++ /* Wait until we get to status-stage, then ack.
++ *
++ * When the UDC sets the UDCCS0[OPR] bit, an interrupt
++ * is supposed to be generated (see 12.5.1 step 14ff, PXA Dev Manual).
++ * That approach didn't work out. Usually a new SETUP command was
++ * already in the fifo. I tried many approaches but was always losing
++ * at least some OPR interrupts. Thus the polling below...
++ */
++ count = 1000;
++ udccs0 = UDCCS0;
++ do
++ {
++ if( (UDCCS0 & UDCCS0_OPR))
++ {
++ /* clear OPR, generate ack */
++ UDCCS0 = UDCCS0_OPR;
++ break;
++ }
++ count--;
++ udelay(1);
++ } while( count);
++
++ PRINTKD( "write fifo: count=%d UDCCS0=%x UDCCS0=%x\n", count, udccs0, UDCCS0);
++ }
++ }
++ /* something goes poopy if I dont wait here ... */
++ udelay(500);
++
++ PRINTKD( "write fifo: bytes sent=%d, bytes left=%d\n", bytes_written, wr.bytes_left);
++}
++
++/*
++ * read_fifo()
++ * Read bytes out of FIFO and put in request.
++ * Called to do the initial read of setup requests
++ * from the host. Return number of bytes read.
++ *
++ */
++static int read_fifo( usb_dev_request_t * request )
++{
++ int bytes_read = 0;
++ unsigned char * pOut = (unsigned char*) request;
++
++ int udccs0 = UDCCS0;
++
++ if( (udccs0 & SETUP_READY) == SETUP_READY)
++ {
++ /* ok it's a setup command */
++ while( UDCCS0 & UDCCS0_RNE)
++ {
++ if( bytes_read >= sizeof( usb_dev_request_t))
++ {
++ /* We've already read enought o fill usb_dev_request_t.
++ * Our tummy is full. Go barf...
++ */
++ printk( "%sread_fifo(): read failure\n", pszMe );
++ usbd_info.stats.ep0_fifo_read_failures++;
++ break;
++ }
++
++ *pOut++ = UDDR0;
++ bytes_read++;
++ }
++ }
++ PRINTKD( "read_fifo %d bytes\n", bytes_read );
++
++ /* clear SA & OPR */
++ UDCCS0 = SETUP_READY;
++
++ usbd_info.stats.ep0_bytes_read += bytes_read;
++ return bytes_read;
++}
++
++/*
++ * get_descriptor()
++ * Called from sh_setup_begin to handle data return
++ * for a GET_DESCRIPTOR setup request.
++ */
++static void get_descriptor( usb_dev_request_t * pReq )
++{
++ string_desc_t * pString;
++ ep_desc_t * pEndpoint = 0;
++
++ desc_t * pDesc = pxa_usb_get_descriptor_ptr();
++ int type = pReq->wValue >> 8;
++ int idx = pReq->wValue & 0xFF;
++
++// PRINTKD( "%sget_descriptor for %d\n", pszMe, type );
++ switch( type ) {
++ case USB_DESC_DEVICE:
++ queue_and_start_write( &pDesc->dev,
++ pReq->wLength,
++ pDesc->dev.bLength );
++ break;
++
++ // return config descriptor buffer, cfg, intf, 2 ep
++ case USB_DESC_CONFIG:
++ queue_and_start_write( &pDesc->b,
++ pReq->wLength,
++ sizeof( struct cdb ) );
++ break;
++
++ // not quite right, since doesn't do language code checking
++ case USB_DESC_STRING:
++ pString = pxa_usb_get_string_descriptor( idx );
++ if ( pString ) {
++ if ( idx != 0 ) { // if not language index
++ printk( "%sReturn string %d: ", pszMe, idx );
++ psdesc( pString );
++ }
++ queue_and_start_write( pString,
++ pReq->wLength,
++ pString->bLength );
++ }
++ else {
++ printk("%sunkown string index %d Stall.\n", pszMe, idx );
++ }
++ break;
++
++ case USB_DESC_INTERFACE:
++ if ( idx == pDesc->b.intf.bInterfaceNumber ) {
++ queue_and_start_write( &pDesc->b.intf,
++ pReq->wLength,
++ pDesc->b.intf.bLength );
++ }
++ break;
++
++ case USB_DESC_ENDPOINT: /* correct? 21Feb01ww */
++ if ( idx == 1 )
++ pEndpoint = &pDesc->b.ep1; //[BULK_IN1];
++ else if ( idx == 2 )
++ pEndpoint = &pDesc->b.ep2; //[BULK_OUT1];
++ else
++ pEndpoint = NULL;
++ if ( pEndpoint ) {
++ queue_and_start_write( pEndpoint,
++ pReq->wLength,
++ pEndpoint->bLength );
++ } else {
++ printk("%sunkown endpoint index %d Stall.\n", pszMe, idx );
++ }
++ break;
++
++
++ default :
++ printk("%sunknown descriptor type %d. Stall.\n", pszMe, type );
++ break;
++
++ }
++}
++
++/* end usb_ep0.c - who needs this comment? */
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/usb_ep0.h
+@@ -0,0 +1,66 @@
++/*
++ * Copyright (C) Intrinsyc, Inc., 2002
++ *
++ * usb_ep0.h - PXA USB controller driver.
++ * Endpoint zero management
++ *
++ * Please see:
++ * linux/Documentation/arm/SA1100/SA1100_USB
++ * for details.
++ *
++ * 02-May-2002
++ * Frank Becker (Intrinsyc) -
++ *
++ */
++
++#ifndef __USB_EP0_H
++#define __USB_EP0_H
++
++#define EP0_FIFO_SIZE 16
++#define SETUP_READY (UDCCS0_SA | UDCCS0_OPR)
++
++/*================================================
++ * USB Protocol Stuff
++ */
++
++/* Request Codes */
++enum {
++ GET_STATUS =0,
++ CLEAR_FEATURE =1,
++ /* reserved =2 */
++ SET_FEATURE =3,
++ /* reserved =4 */
++ SET_ADDRESS =5,
++ GET_DESCRIPTOR =6,
++ SET_DESCRIPTOR =7,
++ GET_CONFIGURATION =8,
++ SET_CONFIGURATION =9,
++ GET_INTERFACE =10,
++ SET_INTERFACE =11,
++ SYNCH_FRAME =12
++};
++
++typedef enum {
++ EP0_IDLE,
++ EP0_IN_DATA_PHASE,
++ EP0_END_XFER,
++ EP0_OUT_DATA_PHASE
++} EP0_state;
++
++/* USB Device Requests */
++typedef struct
++{
++ __u8 bmRequestType;
++ __u8 bRequest;
++ __u16 wValue;
++ __u16 wIndex;
++ __u16 wLength;
++} usb_dev_request_t __attribute__ ((packed));
++
++/* Data extraction from usb_request_t fields */
++enum {
++ kTargetDevice =0,
++ kTargetInterface=1,
++ kTargetEndpoint =2
++};
++#endif
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/usb_recv.c
+@@ -0,0 +1,173 @@
++/*
++ * Generic receive layer for the PXA USB client function
++ *
++ * This code was loosely inspired by the original version which was
++ * Copyright (c) Compaq Computer Corporation, 1998-1999
++ * Copyright (c) 2001 by Nicolas Pitre
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * 02-May-2002
++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_recv.c
++ *
++ * TODO: Add support for DMA.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/errno.h>
++#include <asm/dma.h>
++#include <asm/system.h>
++
++#include "pxa_usb.h"
++#include "usb_ctl.h"
++
++#if DEBUG
++static unsigned int usb_debug = DEBUG;
++#else
++#define usb_debug 0 /* gcc will remove all the debug code for us */
++#endif
++
++static char *ep_bulk_out1_buf;
++static int ep_bulk_out1_len;
++static int ep_bulk_out1_remain;
++static usb_callback_t ep_bulk_out1_callback;
++static int rx_pktsize;
++
++static void
++ep_bulk_out1_start(void)
++{
++ /* disable DMA */
++ UDCCS2 &= ~UDCCS_BO_DME;
++
++ /* enable interrupts for endpoint 2 (bulk out) */
++ UICR0 &= ~UICR0_IM2;
++}
++
++static void
++ep_bulk_out1_done(int flag)
++{
++ int size = ep_bulk_out1_len - ep_bulk_out1_remain;
++
++ if (!ep_bulk_out1_len)
++ return;
++
++ ep_bulk_out1_len = 0;
++ if (ep_bulk_out1_callback) {
++ ep_bulk_out1_callback(flag, size);
++ }
++}
++
++void
++ep_bulk_out1_state_change_notify( int new_state )
++{
++}
++
++void
++ep_bulk_out1_stall( void )
++{
++ /* SET_FEATURE force stall at UDC */
++ UDCCS2 |= UDCCS_BO_FST;
++}
++
++int
++ep_bulk_out1_init(int chn)
++{
++ desc_t * pd = pxa_usb_get_descriptor_ptr();
++ rx_pktsize = __le16_to_cpu( pd->b.ep1.wMaxPacketSize );
++ ep_bulk_out1_done(-EAGAIN);
++ return 0;
++}
++
++void
++ep_bulk_out1_reset(void)
++{
++ desc_t * pd = pxa_usb_get_descriptor_ptr();
++ rx_pktsize = __le16_to_cpu( pd->b.ep1.wMaxPacketSize );
++ UDCCS2 &= ~UDCCS_BO_FST;
++ ep_bulk_out1_done(-EINTR);
++}
++
++void
++ep_bulk_out1_int_hndlr(int udcsr)
++{
++ int status = UDCCS2;
++ if( usb_debug) printk("ep_bulk_out1_int_hndlr: UDCCS2=%x\n", status);
++
++ if( (status & (UDCCS_BO_RNE | UDCCS_BO_RSP)) == UDCCS_BO_RSP)
++ {
++ /* zero-length packet */
++ }
++
++ if( status & UDCCS_BO_RNE)
++ {
++ int len;
++ int i;
++ char *buf = ep_bulk_out1_buf + ep_bulk_out1_len - ep_bulk_out1_remain;
++
++ /* bytes in FIFO */
++ len = (UBCR2 & 0xff) +1;
++
++ if( usb_debug) printk("usb_recv: "
++ "len=%d out1_len=%d out1_remain=%d\n",
++ len,ep_bulk_out1_len,ep_bulk_out1_remain);
++
++ if( len > ep_bulk_out1_remain)
++ {
++ /* FIXME: if this happens, we need a temporary overflow buffer */
++ printk("usb_recv: Buffer overwrite warning...\n");
++ len = ep_bulk_out1_remain;
++ }
++
++ /* read data out of fifo */
++ for( i=0; i<len; i++)
++ {
++ *buf++ = UDDR2 & 0xff;
++ }
++
++ ep_bulk_out1_remain -= len;
++ ep_bulk_out1_done((len) ? 0 : -EPIPE);
++ }
++
++ /* ack RPC - FIXME: '|=' we may ack SST here, too */
++ UDCCS2 |= UDCCS_BO_RPC;
++ return;
++}
++
++int
++pxa_usb_recv(char *buf, int len, usb_callback_t callback)
++{
++ int flags;
++
++ if (ep_bulk_out1_len)
++ return -EBUSY;
++
++ local_irq_save(flags);
++ ep_bulk_out1_buf = buf;
++ ep_bulk_out1_len = len;
++ ep_bulk_out1_callback = callback;
++ ep_bulk_out1_remain = len;
++ ep_bulk_out1_start();
++ local_irq_restore(flags);
++
++ return 0;
++}
++
++void
++pxa_usb_recv_reset(void)
++{
++ ep_bulk_out1_reset();
++}
++
++void
++pxa_usb_recv_stall(void)
++{
++ ep_bulk_out1_stall();
++}
++
++EXPORT_SYMBOL(pxa_usb_recv_stall);
++EXPORT_SYMBOL(pxa_usb_recv);
++EXPORT_SYMBOL(pxa_usb_recv_reset);
+--- /dev/null
++++ linux-2.4.27/arch/arm/mach-pxa/usb_send.c
+@@ -0,0 +1,190 @@
++/*
++ * Generic xmit layer for the PXA USB client function
++ *
++ * This code was loosely inspired by the original version which was
++ * Copyright (c) Compaq Computer Corporation, 1998-1999
++ * Copyright (c) 2001 by Nicolas Pitre
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * 02-May-2002
++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_send.c
++ *
++ * TODO: Add support for DMA.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/errno.h>
++#include <asm/hardware.h>
++#include <asm/dma.h>
++#include <asm/system.h>
++#include <asm/byteorder.h>
++
++#include "pxa_usb.h"
++#include "usb_ctl.h"
++
++#if DEBUG
++static unsigned int usb_debug = DEBUG;
++#else
++#define usb_debug 0 /* gcc will remove all the debug code for us */
++#endif
++
++static char *ep_bulk_in1_buf;
++static int ep_bulk_in1_len;
++static int ep_bulk_in1_remain;
++static usb_callback_t ep_bulk_in1_callback;
++static int tx_pktsize;
++
++/* device state is changing, async */
++void
++ep_bulk_in1_state_change_notify( int new_state )
++{
++}
++
++/* set feature stall executing, async */
++void
++ep_bulk_in1_stall( void )
++{
++ UDCCS1 |= UDCCS_BI_FST;
++}
++
++static void
++ep_bulk_in1_send_packet(void)
++{
++ int i;
++ char *buf = ep_bulk_in1_buf + ep_bulk_in1_len - ep_bulk_in1_remain;
++ int out_size = tx_pktsize;
++
++ if( usb_debug) printk( "ep_bulk_in1_send_packet: UICR0=%x UDCCS1=%x\n", UICR0, UDCCS1);
++
++ if( out_size > ep_bulk_in1_remain)
++ {
++ out_size = ep_bulk_in1_remain;
++ }
++
++ for( i=0; i<out_size; i++)
++ {
++ UDDR1 = *buf++;
++ }
++
++ UDCCS1 = UDCCS_BI_TPC;
++ if( out_size < tx_pktsize)
++ {
++ /* short packet */
++ UDCCS1 = UDCCS_BI_TSP;
++ }
++ ep_bulk_in1_remain -= out_size;
++
++ if( usb_debug) printk( "ep_bulk_in1_send_packet: "
++ "UICR0=%x UDCCS1=%x send bytes=%d left=%d\n",
++ UICR0, UDCCS1, out_size, ep_bulk_in1_remain);
++}
++
++static void
++ep_bulk_in1_start(void)
++{
++ if (!ep_bulk_in1_len)
++ return;
++
++ UICR0 &= ~UICR0_IM1;
++
++ ep_bulk_in1_send_packet();
++}
++
++static void
++ep_bulk_in1_done(int flag)
++{
++ int size = ep_bulk_in1_len - ep_bulk_in1_remain;
++ if (ep_bulk_in1_len) {
++ ep_bulk_in1_len = 0;
++ if (ep_bulk_in1_callback)
++ ep_bulk_in1_callback(flag, size);
++ }
++}
++
++int
++ep_bulk_in1_init(int chn)
++{
++ desc_t * pd = pxa_usb_get_descriptor_ptr();
++ tx_pktsize = __le16_to_cpu( pd->b.ep2.wMaxPacketSize );
++ ep_bulk_in1_done(-EAGAIN);
++ return 0;
++}
++
++void
++ep_bulk_in1_reset(void)
++{
++ desc_t * pd = pxa_usb_get_descriptor_ptr();
++ tx_pktsize = __le16_to_cpu( pd->b.ep2.wMaxPacketSize );
++ UDCCS1 &= ~UDCCS_BI_FST;
++ ep_bulk_in1_done(-EINTR);
++}
++
++void
++ep_bulk_in1_int_hndlr(int usir0)
++{
++ int status = UDCCS1;
++
++ if (ep_bulk_in1_remain != 0) {
++ /* more data to go */
++ ep_bulk_in1_start();
++ } else {
++ if( status & UDCCS_BI_TPC)
++ {
++ UDCCS1 = UDCCS_BI_TPC;
++ }
++ ep_bulk_in1_done(0);
++ }
++}
++
++int
++pxa_usb_send(char *buf, int len, usb_callback_t callback)
++{
++ int flags;
++
++ if( usb_debug) printk( "pxa_usb_send: "
++ "data len=%d state=%d blen=%d\n",
++ len, usbd_info.state, ep_bulk_in1_len);
++
++ if (usbd_info.state != USB_STATE_CONFIGURED)
++ return -ENODEV;
++
++ if (ep_bulk_in1_len)
++ return -EBUSY;
++
++ local_irq_save(flags);
++ ep_bulk_in1_buf = buf;
++ ep_bulk_in1_len = len;
++ ep_bulk_in1_callback = callback;
++ ep_bulk_in1_remain = len;
++ ep_bulk_in1_start();
++ local_irq_restore(flags);
++
++ return 0;
++}
++
++
++void
++pxa_usb_send_reset(void)
++{
++ ep_bulk_in1_reset();
++}
++
++int
++pxa_usb_xmitter_avail( void )
++{
++ if (usbd_info.state != USB_STATE_CONFIGURED)
++ return -ENODEV;
++ if (ep_bulk_in1_len)
++ return -EBUSY;
++ return 0;
++}
++
++
++EXPORT_SYMBOL(pxa_usb_xmitter_avail);
++EXPORT_SYMBOL(pxa_usb_send);
++EXPORT_SYMBOL(pxa_usb_send_reset);
+--- linux-2.4.27/arch/arm/mach-sa1100/sa1111-ohci.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/mach-sa1100/sa1111-ohci.c
+@@ -54,7 +54,7 @@
+ * address as its return value, and the DMA address via
+ * the dma_addr_t pointer.
+ */
+- vbuf = consistent_alloc(GFP_KERNEL | GFP_DMA, 4, &dma_buf);
++ vbuf = consistent_alloc(GFP_KERNEL | GFP_DMA, 4, &dma_buf, 0);
+
+ SADTSA = (unsigned long)dma_buf;
+ SADTCA = 4;
+--- linux-2.4.27/arch/arm/mach-sa1100/sa1111.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/mach-sa1100/sa1111.c
+@@ -243,9 +243,15 @@
+ * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
+ * (SA-1110 Developer's Manual, section 9.1.2.1)
+ */
++#if CONFIG_ARCH_SA1100
+ GAFR |= GPIO_32_768kHz;
+ GPDR |= GPIO_32_768kHz;
+ TUCR = TUCR_3_6864MHz;
++#elif CONFIG_ARCH_PXA
++ set_GPIO_mode(GPIO11_3_6MHz_MD);
++#else
++#error missing clock setup
++#endif
+
+ /*
+ * Turn VCO on, and disable PLL Bypass.
+@@ -300,6 +306,8 @@
+ SBI_SMCR = smcr;
+ }
+
++#ifdef CONFIG_ARCH_SA1100
++
+ /*
+ * Disable the memory bus request/grant signals on the SA1110 to
+ * ensure that we don't receive spurious memory requests. We set
+@@ -341,5 +349,7 @@
+ local_irq_restore(flags);
+ }
+
++#endif
++
+ EXPORT_SYMBOL(sa1111_wake);
+ EXPORT_SYMBOL(sa1111_doze);
+--- linux-2.4.27/arch/arm/mm/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/mm/Makefile
+@@ -44,6 +44,7 @@
+ p-$(CONFIG_CPU_ARM1026) += proc-arm1026.o
+ p-$(CONFIG_CPU_SA110) += proc-sa110.o
+ p-$(CONFIG_CPU_SA1100) += proc-sa110.o
++p-$(CONFIG_CPU_XSCALE) += proc-xscale.o
+
+ # Integrator follows "new style"
+ # Soon, others will do too, and we can get rid of this
+--- linux-2.4.27/arch/arm/mm/consistent.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/mm/consistent.c
+@@ -37,7 +37,8 @@
+ *
+ * Note that this does *not* zero the allocated area!
+ */
+-void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
++void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle,
++ unsigned long cache_flags)
+ {
+ struct page *page, *end, *free;
+ unsigned long order;
+@@ -55,7 +56,7 @@
+ goto no_page;
+
+ *dma_handle = page_to_bus(page);
+- ret = __ioremap(page_to_pfn(page) << PAGE_SHIFT, size, 0);
++ ret = __ioremap(page_to_pfn(page) << PAGE_SHIFT, size, cache_flags);
+ if (!ret)
+ goto no_remap;
+
+@@ -106,7 +107,7 @@
+ #endif
+ gfp |= GFP_DMA;
+
+- return consistent_alloc(gfp, size, handle);
++ return consistent_alloc(gfp, size, handle, 0);
+ }
+
+ /*
+--- linux-2.4.27/arch/arm/mm/init.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/mm/init.c
+@@ -49,6 +49,9 @@
+ static unsigned long totalram_pages;
+ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+ extern char _stext, _text, _etext, _end, __init_begin, __init_end;
++#ifdef CONFIG_XIP_KERNEL
++extern char _endtext, _sdata;
++#endif
+ extern unsigned long phys_initrd_start;
+ extern unsigned long phys_initrd_size;
+
+@@ -347,7 +350,11 @@
+ * Register the kernel text and data with bootmem.
+ * Note that this can only be in node 0.
+ */
++#ifdef CONFIG_XIP_KERNEL
++ reserve_bootmem_node(pgdat, __pa(&_sdata), &_end - &_sdata);
++#else
+ reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
++#endif
+
+ #ifdef CONFIG_CPU_32
+ /*
+@@ -601,8 +608,13 @@
+ unsigned int codepages, datapages, initpages;
+ int i, node;
+
++#ifndef CONFIG_XIP_KERNEL
+ codepages = &_etext - &_text;
+ datapages = &_end - &_etext;
++#else
++ codepages = &_endtext - &_text;
++ datapages = &_end - &_sdata;
++#endif
+ initpages = &__init_end - &__init_begin;
+
+ high_memory = (void *)__va(meminfo.end);
+@@ -658,11 +670,13 @@
+
+ void free_initmem(void)
+ {
++#ifndef CONFIG_XIP_KERNEL
+ if (!machine_is_integrator()) {
+ free_area((unsigned long)(&__init_begin),
+ (unsigned long)(&__init_end),
+ "init");
+ }
++#endif
+ }
+
+ #ifdef CONFIG_BLK_DEV_INITRD
+--- linux-2.4.27/arch/arm/mm/mm-armv.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/arch/arm/mm/mm-armv.c
+@@ -356,6 +356,19 @@
+ p ++;
+ #endif
+
++#ifdef CONFIG_XIP_KERNEL
++ p->physical = KERNEL_XIP_BASE_PHYS;
++ p->virtual = KERNEL_XIP_BASE_VIRT;
++ p->length = PGDIR_SIZE * 8;
++ p->domain = DOMAIN_KERNEL;
++ p->prot_read = 0; /* r=0, b=0 --> read-only for kernel mode */
++ p->prot_write = 0;
++ p->cacheable = 1;
++ p->bufferable = 1;
++
++ p ++;
++#endif
++
+ /*
+ * Go through the initial mappings, but clear out any
+ * pgdir entries that are not in the description.
+@@ -386,7 +399,7 @@
+ init_maps->prot_read = 0;
+ init_maps->prot_write = 0;
+ init_maps->cacheable = 1;
+- init_maps->bufferable = 0;
++ init_maps->bufferable = 1;
+
+ create_mapping(init_maps);
+
+--- /dev/null
++++ linux-2.4.27/arch/arm/mm/proc-xscale.S
+@@ -0,0 +1,1086 @@
++/*
++ * linux/arch/arm/mm/proc-xscale.S
++ *
++ * Author: Nicolas Pitre
++ * Created: November 2000
++ * Copyright: (C) 2000, 2001 MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * MMU functions for the Intel XScale CPUs
++ *
++ * 2001 Aug 21:
++ * some contributions by Brett Gaines <brett.w.gaines@intel.com>
++ * Copyright 2001 by Intel Corp.
++ *
++ * 2001 Sep 08:
++ * Completely revisited, many important fixes
++ * Nicolas Pitre <nico@cam.org>
++ */
++
++#include <linux/config.h>
++#include <linux/linkage.h>
++#include <asm/assembler.h>
++#include <asm/constants.h>
++#include <asm/procinfo.h>
++#include <asm/hardware.h>
++#include <asm/proc/pgtable.h>
++
++/*
++ * Some knobs for cache allocation policy.
++ * Allocate on write may or may not be beneficial depending on the memory
++ * usage pattern of your main application. Write through cache is definitely
++ * a performance loss in most cases, but might be used for special purposes.
++ */
++#define PMD_CACHE_WRITE_ALLOCATE 1
++#define PTE_CACHE_WRITE_ALLOCATE 1
++#define CACHE_WRITE_THROUGH 0
++
++/*
++ * There are errata that say that dirty status bits in the cache may get
++ * corrupted. The workaround significantly affects performance, and the bug
++ * _might_ just not be that visible or critical to you, so it is configurable.
++ * Let's hope a future core revision will tell us this was only a bad dream.
++ * But in the mean time the risk and tradeoff is yours to decide....
++ */
++#ifdef CONFIG_XSCALE_CACHE_ERRATA
++#undef CACHE_WRITE_THROUGH
++#define CACHE_WRITE_THROUGH 1
++#endif
++
++/*
++ * This is the maximum size of an area which will be flushed. If the area
++ * is larger than this, then we flush the whole cache
++ */
++#define MAX_AREA_SIZE 32768
++
++/*
++ * the cache line size of the I and D cache
++ */
++#define CACHELINESIZE 32
++
++/*
++ * the size of the data cache
++ */
++#define CACHESIZE 32768
++
++/*
++ * and the page size
++ */
++#define PAGESIZE 4096
++
++/*
++ * Virtual address used to allocate the cache when flushed
++ *
++ * This must be an address range which is _never_ used. It should
++ * apparently have a mapping in the corresponding page table for
++ * compatibility with future CPUs that _could_ require it. For instance we
++ * don't care.
++ *
++ * This must be aligned on a 2*CACHESIZE boundary. The code selects one of
++ * the 2 areas in alternance each time the clean_d_cache macro is used.
++ * Without this the XScale core exhibits cache eviction problems and no one
++ * knows why.
++ *
++ * Reminder: the vector table is located at 0xffff0000-0xffff0fff.
++ */
++#define CLEAN_ADDR 0xfffe0000
++
++/*
++ * This macro is used to wait for a CP15 write and is needed
++ * when we have to ensure that the last operation to the co-pro
++ * was completed before continuing with operation.
++ */
++ .macro cpwait, rd
++ mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15
++ mov \rd, \rd @ wait for completion
++ sub pc, pc, #4 @ flush instruction pipeline
++ .endm
++
++ .macro cpwait_ret, lr, rd
++ mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15
++ sub pc, \lr, \rd, LSR #32 @ wait for completion and
++ @ flush instruction pipeline
++ .endm
++
++#if !CACHE_WRITE_THROUGH
++
++/*
++ * This macro cleans the entire dcache using line allocate.
++ * The main loop has been unrolled to reduce loop overhead.
++ * rd and rs are two scratch registers.
++ */
++ .macro clean_d_cache, rd, rs
++ ldr \rs, =clean_addr
++ ldr \rd, [\rs]
++ eor \rd, \rd, #CACHESIZE
++ str \rd, [\rs]
++ add \rs, \rd, #CACHESIZE
++1: mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line
++ add \rd, \rd, #CACHELINESIZE
++ mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line
++ add \rd, \rd, #CACHELINESIZE
++ mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line
++ add \rd, \rd, #CACHELINESIZE
++ mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line
++ add \rd, \rd, #CACHELINESIZE
++ teq \rd, \rs
++ bne 1b
++ .endm
++
++ .macro clean_d_line, rd
++ mcr p15, 0, \rd, c7, c10, 1
++ .endm
++
++ .data
++clean_addr: .word CLEAN_ADDR
++
++#else
++
++/*
++ * If cache is write-through, there is no need to clean it.
++ * Simply invalidating will do.
++ */
++
++ .macro clean_d_cache, rd, rs
++ mcr p15, 0, \rd, c7, c6, 0
++ .endm
++
++ /* let's try to skip this needless operations at least within loops */
++ .macro clean_d_line, rd
++ .endm
++
++#endif
++
++ .text
++
++/*
++ * cpu_xscale_data_abort()
++ *
++ * obtain information about current aborted instruction.
++ * Note: we read user space. This means we might cause a data
++ * abort here if the I-TLB and D-TLB aren't seeing the same
++ * picture. Unfortunately, this does happen. We live with it.
++ *
++ * r2 = address of aborted instruction
++ * r3 = saved SPSR
++ *
++ * Returns:
++ * r0 = address of abort
++ * r1 = FSR, bit 11 = write
++ * r3 = corrupted
++ */
++ .align 5
++ENTRY(cpu_xscale_data_abort)
++ mrc p15, 0, r1, c5, c0, 0 @ get FSR
++ mrc p15, 0, r0, c6, c0, 0 @ get FAR
++ ldr r3, [r2] @ read aborted instruction
++ bic r1, r1, #1 << 11 @ clear bits 11 of FSR
++ tst r3, #1 << 20 @ check write
++ orreq r1, r1, #1 << 11
++ mov pc, lr
++
++/*
++ * cpu_xscale_check_bugs()
++ */
++ENTRY(cpu_xscale_check_bugs)
++ mrs ip, cpsr
++ bic ip, ip, #F_BIT
++ msr cpsr, ip
++ mov pc, lr
++
++#ifndef CONFIG_XSCALE_CACHE_ERRATA
++/*
++ * cpu_xscale_proc_init()
++ *
++ * Nothing too exciting at the moment
++ */
++ENTRY(cpu_xscale_proc_init)
++ mov pc, lr
++#else
++/*
++ * We enable the cache here, but we make sure all the status bits for dirty
++ * lines are cleared as well (see PXA250 erratum #120).
++ */
++ENTRY(cpu_xscale_proc_init)
++ @ enable data cache
++ ldr r0, cr_p
++ ldmia r0, {r1, r2}
++ orr r1, r1, #0x4
++ orr r2, r2, #0x4
++ stmia r0, {r1, r2}
++ mcr p15, 0, r1, c1, c0, 0
++ cpwait r0
++
++ @ invalidate data cache
++ mcr p15, 0, r0, c7, c6, 0
++
++ @ fill main cache with write-through lines
++ bic r0, pc, #0x1f
++ add r1, r0, #CACHESIZE
++1: ldr r2, [r0], #32
++ cmp r0, r1
++ bne 1b
++
++ @ enable test feature to force all fills to the mini-cache
++ mov r1, #0x8
++ mcr p15, 0, r1, c15, c15, 3
++
++ @ fill mini-cache with write-through lines (2kbytes, 64 lines)
++ add r1, r0, #2048
++2: ldr r2, [r0], #32
++ cmp r0, r1
++ bne 2b
++
++ @ disable test feature to force all fills to the mini-cache
++ mov r1, #0x0
++ mcr p15, 0, r1, c15, c15, 3
++
++ @ invalidate data cache again
++ mcr p15, 0, r1, c7, c6, 0
++ mov pc, lr
++
++cr_p: .long SYMBOL_NAME(cr_alignment)
++#endif
++
++/*
++ * cpu_xscale_proc_fin()
++ */
++ENTRY(cpu_xscale_proc_fin)
++ str lr, [sp, #-4]!
++ mov r0, #F_BIT|I_BIT|SVC_MODE
++ msr cpsr_c, r0
++ mrc p15, 0, r0, c1, c0, 0 @ ctrl register
++ bic r0, r0, #0x1800 @ ...IZ...........
++ bic r0, r0, #0x0006 @ .............CA.
++ mcr p15, 0, r0, c1, c0, 0 @ disable caches
++ bl cpu_xscale_cache_clean_invalidate_all @ clean caches
++ ldr pc, [sp], #4
++
++/*
++ * cpu_xscale_reset(loc)
++ *
++ * Perform a soft reset of the system. Put the CPU into the
++ * same state as it would be if it had been reset, and branch
++ * to what would be the reset vector.
++ *
++ * loc: location to jump to for soft reset
++ */
++ .align 5
++ENTRY(cpu_xscale_reset)
++ mov r1, #F_BIT|I_BIT|SVC_MODE
++ msr cpsr_c, r1 @ reset CPSR
++ mrc p15, 0, r1, c1, c0, 0 @ ctrl register
++ bic r1, r1, #0x0086 @ ........B....CA.
++ bic r1, r1, #0x1900 @ ...IZ..S........
++ mcr p15, 0, r1, c1, c0, 0 @ ctrl register
++ mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches & BTB
++ bic r1, r1, #0x0001 @ ...............M
++ mcr p15, 0, r1, c1, c0, 0 @ ctrl register
++ @ CAUTION: MMU turned off from this point. We count on the pipeline
++ @ already containing those two last instructions to survive.
++ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
++ mov pc, r0
++
++/*
++ * cpu_xscale_do_idle(type)
++ *
++ * Cause the processor to idle
++ *
++ * type:
++ * 0 = slow idle
++ * 1 = fast idle
++ * 2 = switch to slow processor clock
++ * 3 = switch to fast processor clock
++ *
++ * For now we do nothing but go to idle mode for every case
++ *
++ * XScale supports clock switching, but using idle mode support
++ * allows external hardware to react to system state changes.
++ */
++ .align 5
++
++ENTRY(cpu_xscale_do_idle)
++ mov r0, #1
++ mcr p14, 0, r0, c7, c0, 0 @ Go to IDLE
++ mov pc, lr
++
++/* ================================= CACHE ================================ */
++
++/*
++ * cpu_xscale_cache_clean_invalidate_all (void)
++ *
++ * clean and invalidate all cache lines
++ *
++ * Note:
++ * 1. We should preserve r0 at all times.
++ * 2. Even if this function implies cache "invalidation" by its name,
++ * we don't need to actually use explicit invalidation operations
++ * since the goal is to discard all valid references from the cache
++ * and the cleaning of it already has that effect.
++ * 3. Because of 2 above and the fact that kernel space memory is always
++ * coherent across task switches there is no need to worry about
++ * inconsistencies due to interrupts, ence no irq disabling.
++ */
++ .align 5
++ENTRY(cpu_xscale_cache_clean_invalidate_all)
++ mov r2, #1
++cpu_xscale_cache_clean_invalidate_all_r2:
++ clean_d_cache r0, r1
++ teq r2, #0
++ mcrne p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mov pc, lr
++
++/*
++ * cpu_xscale_cache_clean_invalidate_range(start, end, flags)
++ *
++ * clean and invalidate all cache lines associated with this area of memory
++ *
++ * start: Area start address
++ * end: Area end address
++ * flags: nonzero for I cache as well
++ */
++ .align 5
++ENTRY(cpu_xscale_cache_clean_invalidate_range)
++ bic r0, r0, #CACHELINESIZE - 1 @ round down to cache line
++ sub r3, r1, r0
++ cmp r3, #MAX_AREA_SIZE
++ bhi cpu_xscale_cache_clean_invalidate_all_r2
++1: clean_d_line r0 @ Clean D cache line
++ mcr p15, 0, r0, c7, c6, 1 @ Invalidate D cache line
++ add r0, r0, #CACHELINESIZE
++ cmp r0, r1
++ blo 1b
++ teq r2, #0
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ moveq pc, lr
++ sub r0, r0, r3
++1: mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line
++ add r0, r0, #CACHELINESIZE
++ cmp r0, r1
++ blo 1b
++ mcr p15, 0, ip, c7, c5, 6 @ Invalidate BTB
++ mov pc, lr
++
++/*
++ * cpu_xscale_flush_ram_page(page)
++ *
++ * clean all cache lines associated with this memory page
++ *
++ * page: page to clean
++ */
++ .align 5
++ENTRY(cpu_xscale_flush_ram_page)
++#if !CACHE_WRITE_THROUGH
++ mov r1, #PAGESIZE
++1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ add r0, r0, #CACHELINESIZE
++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ add r0, r0, #CACHELINESIZE
++ subs r1, r1, #2 * CACHELINESIZE
++ bne 1b
++#endif
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mov pc, lr
++
++/* ================================ D-CACHE =============================== */
++
++/*
++ * cpu_xscale_dcache_invalidate_range(start, end)
++ *
++ * throw away all D-cached data in specified region without an obligation
++ * to write them back. Note however that on XScale we must clean all
++ * entries also due to hardware errata (80200 A0 & A1 only).
++ *
++ * start: virtual start address
++ * end: virtual end address
++ */
++ .align 5
++ENTRY(cpu_xscale_dcache_invalidate_range)
++ mrc p15, 0, r2, c0, c0, 0 @ Read part no.
++ eor r2, r2, #0x69000000
++ eor r2, r2, #0x00052000 @ 80200 XX part no.
++ bics r2, r2, #0x1 @ Clear LSB in revision field
++ moveq r2, #0
++ beq cpu_xscale_cache_clean_invalidate_range @ An 80200 A0 or A1
++
++ tst r0, #CACHELINESIZE - 1
++ mcrne p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ tst r1, #CACHELINESIZE - 1
++ mcrne p15, 0, r1, c7, c10, 1 @ Clean D cache line
++ bic r0, r0, #CACHELINESIZE - 1 @ round down to cache line
++1: mcr p15, 0, r0, c7, c6, 1 @ Invalidate D cache line
++ add r0, r0, #CACHELINESIZE
++ cmp r0, r1
++ blo 1b
++ mov pc, lr
++
++/*
++ * cpu_xscale_dcache_clean_range(start, end)
++ *
++ * For the specified virtual address range, ensure that all caches contain
++ * clean data, such that peripheral accesses to the physical RAM fetch
++ * correct data.
++ *
++ * start: virtual start address
++ * end: virtual end address
++ */
++ .align 5
++ENTRY(cpu_xscale_dcache_clean_range)
++#if !CACHE_WRITE_THROUGH
++ bic r0, r0, #CACHELINESIZE - 1
++ sub r2, r1, r0
++ cmp r2, #MAX_AREA_SIZE
++ movhi r2, #0
++ bhi cpu_xscale_cache_clean_invalidate_all_r2
++
++1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ add r0, r0, #CACHELINESIZE
++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ add r0, r0, #CACHELINESIZE
++ cmp r0, r1
++ blo 1b
++#endif
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mov pc, lr
++
++/*
++ * cpu_xscale_clean_dcache_page(page)
++ *
++ * Cleans a single page of dcache so that if we have any future aliased
++ * mappings, they will be consistent at the time that they are created.
++ *
++ * Note:
++ * 1. we don't need to flush the write buffer in this case. [really? -Nico]
++ * 2. we don't invalidate the entries since when we write the page
++ * out to disk, the entries may get reloaded into the cache.
++ */
++ .align 5
++ENTRY(cpu_xscale_dcache_clean_page)
++#if !CACHE_WRITE_THROUGH
++ mov r1, #PAGESIZE
++1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ add r0, r0, #CACHELINESIZE
++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ add r0, r0, #CACHELINESIZE
++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ add r0, r0, #CACHELINESIZE
++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ add r0, r0, #CACHELINESIZE
++ subs r1, r1, #4 * CACHELINESIZE
++ bne 1b
++#endif
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mov pc, lr
++
++/*
++ * cpu_xscale_dcache_clean_entry(addr)
++ *
++ * Clean the specified entry of any caches such that the MMU
++ * translation fetches will obtain correct data.
++ *
++ * addr: cache-unaligned virtual address
++ */
++ .align 5
++ENTRY(cpu_xscale_dcache_clean_entry)
++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mov pc, lr
++
++/* ================================ I-CACHE =============================== */
++
++/*
++ * cpu_xscale_icache_invalidate_range(start, end)
++ *
++ * invalidate a range of virtual addresses from the Icache
++ *
++ * start: virtual start address
++ * end: virtual end address
++ *
++ * Note: This is vaguely defined as supposed to bring the dcache and the
++ * icache in sync by the way this function is used.
++ */
++ .align 5
++ENTRY(cpu_xscale_icache_invalidate_range)
++ bic r0, r0, #CACHELINESIZE - 1
++1: clean_d_line r0 @ Clean D cache line
++ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line
++ add r0, r0, #CACHELINESIZE
++ cmp r0, r1
++ blo 1b
++ mcr p15, 0, ip, c7, c5, 6 @ Invalidate BTB
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mov pc, lr
++
++/*
++ * cpu_xscale_icache_invalidate_page(page)
++ *
++ * invalidate all Icache lines associated with this area of memory
++ *
++ * page: page to invalidate
++ */
++ .align 5
++ENTRY(cpu_xscale_icache_invalidate_page)
++ mov r1, #PAGESIZE
++1: mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line
++ add r0, r0, #CACHELINESIZE
++ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line
++ add r0, r0, #CACHELINESIZE
++ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line
++ add r0, r0, #CACHELINESIZE
++ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line
++ add r0, r0, #CACHELINESIZE
++ subs r1, r1, #4 * CACHELINESIZE
++ bne 1b
++ mcr p15, 0, r0, c7, c5, 6 @ Invalidate BTB
++ mov pc, lr
++
++/* ================================ CACHE LOCKING============================
++ *
++ * The XScale MicroArchitecture implements support for locking entries into
++ * the data and instruction cache. The following functions implement the core
++ * low level instructions needed to accomplish the locking. The developer's
++ * manual states that the code that performs the locking must be in non-cached
++ * memory. To accomplish this, the code in xscale-cache-lock.c copies the
++ * following functions from the cache into a non-cached memory region that
++ * is allocated through consistent_alloc().
++ *
++ */
++ .align 5
++/*
++ * xscale_icache_lock
++ *
++ * r0: starting address to lock
++ * r1: end address to lock
++ */
++ENTRY(xscale_icache_lock)
++
++iLockLoop:
++ bic r0, r0, #CACHELINESIZE - 1
++ mcr p15, 0, r0, c9, c1, 0 @ lock into cache
++ cmp r0, r1 @ are we done?
++ add r0, r0, #CACHELINESIZE @ advance to next cache line
++ bls iLockLoop
++ mov pc, lr
++
++/*
++ * xscale_icache_unlock
++ */
++ENTRY(xscale_icache_unlock)
++ mcr p15, 0, r0, c9, c1, 1 @ Unlock icache
++ mov pc, lr
++
++/*
++ * xscale_dcache_lock
++ *
++ * r0: starting address to lock
++ * r1: end address to lock
++ */
++ENTRY(xscale_dcache_lock)
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mov r2, #1
++ mcr p15, 0, r2, c9, c2, 0 @ Put dcache in lock mode
++ cpwait ip @ Wait for completion
++
++ mrs r2, cpsr
++ orr r3, r2, #F_BIT | I_BIT
++dLockLoop:
++ msr cpsr_c, r3
++ mcr p15, 0, r0, c7, c10, 1 @ Write back line if it is dirty
++ mcr p15, 0, r0, c7, c6, 1 @ Flush/invalidate line
++ msr cpsr_c, r2
++ ldr ip, [r0], #CACHELINESIZE @ Preload 32 bytes into cache from
++ @ location [r0]. Post-increment
++ @ r3 to next cache line
++ cmp r0, r1 @ Are we done?
++ bls dLockLoop
++
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mov r2, #0
++ mcr p15, 0, r2, c9, c2, 0 @ Get out of lock mode
++ cpwait_ret lr, ip
++
++/*
++ * xscale_dcache_unlock
++ */
++ENTRY(xscale_dcache_unlock)
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mcr p15, 0, ip, c9, c2, 1 @ Unlock cache
++ mov pc, lr
++
++/*
++ * Needed to determine the length of the code that needs to be copied.
++ */
++ .align 5
++ENTRY(xscale_cache_dummy)
++ mov pc, lr
++
++/* ================================== TLB ================================= */
++
++/*
++ * cpu_xscale_tlb_invalidate_all()
++ *
++ * Invalidate all TLB entries
++ */
++ .align 5
++ENTRY(cpu_xscale_tlb_invalidate_all)
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
++ cpwait_ret lr, ip
++
++/*
++ * cpu_xscale_tlb_invalidate_range(start, end)
++ *
++ * invalidate TLB entries covering the specified range
++ *
++ * start: range start address
++ * end: range end address
++ */
++ .align 5
++ENTRY(cpu_xscale_tlb_invalidate_range)
++ bic r0, r0, #(PAGESIZE - 1) & 0x00ff
++ bic r0, r0, #(PAGESIZE - 1) & 0xff00
++ sub r3, r1, r0
++ cmp r3, #256 * PAGESIZE @ arbitrary, should be tuned
++ bhi cpu_xscale_tlb_invalidate_all
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
++ mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry
++ add r0, r0, #PAGESIZE
++ cmp r0, r1
++ blo 1b
++ cpwait_ret lr, ip
++
++/*
++ * cpu_xscale_tlb_invalidate_page(page, flags)
++ *
++ * invalidate the TLB entries for the specified page.
++ *
++ * page: page to invalidate
++ * flags: non-zero if we include the I TLB
++ */
++ .align 5
++ENTRY(cpu_xscale_tlb_invalidate_page)
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ teq r1, #0
++ mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
++ mcrne p15, 0, r3, c8, c5, 1 @ invalidate I TLB entry
++ cpwait_ret lr, ip
++
++/* ================================ TLB LOCKING==============================
++ *
++ * The XScale MicroArchitecture implements support for locking entries into
++ * the Instruction and Data TLBs. The following functions provide the
++ * low level support for supporting these under Linux. xscale-lock.c
++ * implements some higher level management code. Most of the following
++ * is taken straight out of the Developer's Manual.
++ */
++
++/*
++ * Lock I-TLB entry
++ *
++ * r0: Virtual address to translate and lock
++ */
++ .align 5
++ENTRY(xscale_itlb_lock)
++ mrs r2, cpsr
++ orr r3, r2, #F_BIT | I_BIT
++ msr cpsr_c, r3 @ Disable interrupts
++ mcr p15, 0, r0, c8, c5, 1 @ Invalidate I-TLB entry
++ mcr p15, 0, r0, c10, c4, 0 @ Translate and lock
++ msr cpsr_c, r2 @ Restore interrupts
++ cpwait_ret lr, ip
++
++/*
++ * Lock D-TLB entry
++ *
++ * r0: Virtual address to translate and lock
++ */
++ .align 5
++ENTRY(xscale_dtlb_lock)
++ mrs r2, cpsr
++ orr r3, r2, #F_BIT | I_BIT
++ msr cpsr_c, r3 @ Disable interrupts
++ mcr p15, 0, r0, c8, c6, 1 @ Invalidate D-TLB entry
++ mcr p15, 0, r0, c10, c8, 0 @ Translate and lock
++ msr cpsr_c, r2 @ Restore interrupts
++ cpwait_ret lr, ip
++
++/*
++ * Unlock all I-TLB entries
++ */
++ .align 5
++ENTRY(xscale_itlb_unlock)
++ mcr p15, 0, ip, c10, c4, 1 @ Unlock I-TLB
++ mcr p15, 0, ip, c8, c5, 0 @ Invalidate I-TLB
++ cpwait_ret lr, ip
++
++/*
++ * Unlock all D-TLB entries
++ */
++ENTRY(xscale_dtlb_unlock)
++ mcr p15, 0, ip, c10, c8, 1 @ Unlock D-TBL
++ mcr p15, 0, ip, c8, c6, 0 @ Invalidate D-TLB
++ cpwait_ret lr, ip
++
++/* =============================== PageTable ============================== */
++
++/*
++ * cpu_xscale_set_pgd(pgd)
++ *
++ * Set the translation base pointer to be as described by pgd.
++ *
++ * pgd: new page tables
++ */
++ .align 5
++ENTRY(cpu_xscale_set_pgd)
++ clean_d_cache r1, r2
++ mcr p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
++ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
++ cpwait_ret lr, ip
++
++/*
++ * cpu_xscale_set_pmd(pmdp, pmd)
++ *
++ * Set a level 1 translation table entry, and clean it out of
++ * any caches such that the MMUs can load it correctly.
++ *
++ * pmdp: pointer to PMD entry
++ * pmd: PMD value to store
++ */
++ .align 5
++ENTRY(cpu_xscale_set_pmd)
++#if PMD_CACHE_WRITE_ALLOCATE && !CACHE_WRITE_THROUGH
++ and r2, r1, #PMD_TYPE_MASK|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE
++ cmp r2, #PMD_TYPE_SECT|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE
++ orreq r1, r1, #PMD_SECT_TEX(1)
++#elif CACHE_WRITE_THROUGH
++ and r2, r1, #PMD_TYPE_MASK|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE
++ cmp r2, #PMD_TYPE_SECT|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE
++ biceq r1, r1, #PMD_SECT_BUFFERABLE
++#endif
++ str r1, [r0]
++ mov ip, #0
++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mov pc, lr
++
++/*
++ * cpu_xscale_set_pte(ptep, pte)
++ *
++ * Set a PTE and flush it out
++ *
++ * Errata 40: must set memory to write-through for user read-only pages.
++ */
++ .align 5
++ENTRY(cpu_xscale_set_pte)
++ str r1, [r0], #-1024 @ linux version
++
++ bic r2, r1, #0xff0
++ orr r2, r2, #PTE_TYPE_EXT @ extended page
++
++ eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
++
++ tst r3, #L_PTE_USER | L_PTE_EXEC @ User or Exec?
++ orrne r2, r2, #PTE_EXT_AP_URO_SRW @ yes -> user r/o, system r/w
++
++ tst r3, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
++ orreq r2, r2, #PTE_EXT_AP_UNO_SRW @ yes -> user n/a, system r/w
++ @ combined with user -> user r/w
++
++ @
++ @ Handle the X bit. We want to set this bit for the minicache
++ @ (U = E = B = W = 0, C = 1) or when write allocate is enabled,
++ @ and we have a writeable, cacheable region. If we ignore the
++ @ U and E bits, we can allow user space to use the minicache as
++ @ well.
++ @
++ @ X = C & ~W & ~B
++ @ | C & W & B & write_allocate
++ @
++ eor ip, r1, #L_PTE_CACHEABLE
++ tst ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
++#if PTE_CACHE_WRITE_ALLOCATE && !CACHE_WRITE_THROUGH
++ eorne ip, r1, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
++ tstne ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
++#endif
++ orreq r2, r2, #PTE_EXT_TEX(1)
++
++#if CACHE_WRITE_THROUGH
++ tst r1, #L_PTE_CACHEABLE
++ bicne r2, r2, #L_PTE_BUFFERABLE @ clear B only if C is set
++#else
++ @
++ @ Errata 40: The B bit must be cleared for a user read-only
++ @ cacheable page.
++ @
++ @ B = B & ~((U|E) & C & ~W)
++ @
++ and ip, r1, #L_PTE_USER | L_PTE_EXEC | L_PTE_WRITE | L_PTE_CACHEABLE
++ teq ip, #L_PTE_USER | L_PTE_CACHEABLE
++ teqne ip, #L_PTE_EXEC | L_PTE_CACHEABLE
++ teqne ip, #L_PTE_USER | L_PTE_EXEC | L_PTE_CACHEABLE
++ biceq r2, r2, #PTE_BUFFERABLE
++#endif
++
++ tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
++ movne r2, #0 @ no -> fault
++
++ str r2, [r0] @ hardware version
++
++ @ We try to map 64K page entries when possible.
++ @ We do that for kernel space only since the usage pattern from
++ @ the setting of VM area is quite simple. User space is not worth
++ @ the implied complexity because of ever randomly changing PTEs
++ @ (page aging, swapout, etc) requiring constant coherency checks.
++ @ Since PTEs are usually set in increasing order, we test the
++ @ possibility for a large page only when given the last PTE of a
++ @ 64K boundary.
++ tsteq r1, #L_PTE_USER
++ andeq r1, r0, #(15 << 2)
++ teqeq r1, #(15 << 2)
++ beq 1f
++
++ mov ip, #0
++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mov pc, lr
++
++ @ See if we have 16 identical PTEs but with consecutive base addresses
++1: bic r3, r2, #0x0000f000
++ mov r1, #0x0000f000
++2: eor r2, r2, r3
++ teq r2, r1
++ bne 4f
++ subs r1, r1, #0x00001000
++ ldr r2, [r0, #-4]!
++ bne 2b
++ eors r2, r2, r3
++ bne 4f
++
++ @ Now create our LARGE PTE from the current EXT one.
++ bic r3, r3, #PTE_TYPE_MASK
++ orr r3, r3, #PTE_TYPE_LARGE
++ and r2, r3, #0x30 @ EXT_AP --> LARGE_AP0
++ orr r2, r2, r2, lsl #2 @ add LARGE_AP1
++ orr r2, r2, r2, lsl #4 @ add LARGE_AP3 + LARGE_AP2
++ and r1, r3, #0x3c0 @ EXT_TEX
++ bic r3, r3, #0x3c0
++ orr r2, r2, r1, lsl #(12 - 6) @ --> LARGE_TEX
++ orr r2, r2, r3 @ add remaining bits
++
++ @ then put it in the pagetable
++ mov r3, r2
++3: strd r2, [r0], #8
++ tst r0, #(15 << 2)
++ bne 3b
++
++ @ Then sync the 2 corresponding cache lines
++ sub r0, r0, #(16 << 2)
++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++4: orr r0, r0, #(15 << 2)
++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
++ mov ip, #0
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mov pc, lr
++
++ .ltorg
++
++cpu_manu_name:
++ .asciz "Intel"
++
++cpu_80200_name:
++ .asciz "XScale-80200"
++
++cpu_pxa210_name:
++ .asciz "XScale-PXA210"
++
++cpu_pxa250_name:
++ .asciz "XScale-PXA250"
++
++cpu_pxa255_name:
++ .asciz "XScale-PXA255"
++
++ .align
++
++ .section ".text.init", #alloc, #execinstr
++
++__xscale_setup:
++ mov r0, #F_BIT|I_BIT|SVC_MODE
++ msr cpsr_c, r0
++ mcr p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB
++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
++ mcr p15, 0, ip, c8, c7, 0 @ invalidate I, D TLBs
++ mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
++ mov r0, #0x1f @ Domains 0, 1 = client
++ mcr p15, 0, r0, c3, c0, 0 @ load domain access register
++ mov r0, #1 @ Allow user space to access
++ mcr p15, 0, r0, c15, c1, 0 @ ... CP 0 only.
++#if CACHE_WRITE_THROUGH
++ mov r0, #0x20
++#else
++ mov r0, #0x00
++#endif
++ mcr p15, 0, r0, c1, c1, 0 @ set auxiliary control reg
++ mrc p15, 0, r0, c1, c0, 0 @ get control register
++ bic r0, r0, #0x0200 @ ......R.........
++ bic r0, r0, #0x0082 @ ........B.....A.
++ orr r0, r0, #0x0005 @ .............C.M
++ orr r0, r0, #0x3900 @ ..VIZ..S........
++#ifdef CONFIG_XSCALE_CACHE_ERRATA
++ bic r0, r0, #0x0004 @ see cpu_xscale_proc_init
++#endif
++ mov pc, lr
++
++ .text
++
++/*
++ * Purpose : Function pointers used to access above functions - all calls
++ * come through these
++ */
++
++ .type xscale_processor_functions, #object
++ENTRY(xscale_processor_functions)
++ .word cpu_xscale_data_abort
++ .word cpu_xscale_check_bugs
++ .word cpu_xscale_proc_init
++ .word cpu_xscale_proc_fin
++ .word cpu_xscale_reset
++ .word cpu_xscale_do_idle
++
++ /* cache */
++ .word cpu_xscale_cache_clean_invalidate_all
++ .word cpu_xscale_cache_clean_invalidate_range
++ .word cpu_xscale_flush_ram_page
++
++ /* dcache */
++ .word cpu_xscale_dcache_invalidate_range
++ .word cpu_xscale_dcache_clean_range
++ .word cpu_xscale_dcache_clean_page
++ .word cpu_xscale_dcache_clean_entry
++
++ /* icache */
++ .word cpu_xscale_icache_invalidate_range
++ .word cpu_xscale_icache_invalidate_page
++
++ /* tlb */
++ .word cpu_xscale_tlb_invalidate_all
++ .word cpu_xscale_tlb_invalidate_range
++ .word cpu_xscale_tlb_invalidate_page
++
++ /* pgtable */
++ .word cpu_xscale_set_pgd
++ .word cpu_xscale_set_pmd
++ .word cpu_xscale_set_pte
++ .size xscale_processor_functions, . - xscale_processor_functions
++
++ .type cpu_80200_info, #object
++cpu_80200_info:
++ .long cpu_manu_name
++ .long cpu_80200_name
++ .size cpu_80200_info, . - cpu_80200_info
++
++ .type cpu_pxa210_info, #object
++cpu_pxa210_info:
++ .long cpu_manu_name
++ .long cpu_pxa210_name
++ .size cpu_pxa210_info, . - cpu_pxa210_info
++
++ .type cpu_pxa250_info, #object
++cpu_pxa250_info:
++ .long cpu_manu_name
++ .long cpu_pxa250_name
++ .size cpu_pxa250_info, . - cpu_pxa250_info
++
++ .type cpu_pxa255_info, #object
++cpu_pxa255_info:
++ .long cpu_manu_name
++ .long cpu_pxa255_name
++ .size cpu_pxa255_info, . - cpu_pxa255_info
++
++ .type cpu_arch_name, #object
++cpu_arch_name:
++ .asciz "armv5te"
++ .size cpu_arch_name, . - cpu_arch_name
++
++ .type cpu_elf_name, #object
++cpu_elf_name:
++ .asciz "v5"
++ .size cpu_elf_name, . - cpu_elf_name
++ .align
++
++ .section ".proc.info", #alloc, #execinstr
++
++ .type __80200_proc_info,#object
++__80200_proc_info:
++ .long 0x69052000
++ .long 0xfffffff0
++#if CACHE_WRITE_THROUGH
++ .long 0x00000c0a
++#else
++ .long 0x00000c0e
++#endif
++ b __xscale_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE
++ .long cpu_80200_info
++ .long xscale_processor_functions
++ .size __80200_proc_info, . - __80200_proc_info
++
++ .type __pxa210_proc_info,#object
++__pxa210_proc_info:
++ .long 0x69052120
++ .long 0xfffff3f0
++#if CACHE_WRITE_THROUGH
++ .long 0x00000c0a
++#else
++ .long 0x00000c0e
++#endif
++ b __xscale_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE
++ .long cpu_pxa210_info
++ .long xscale_processor_functions
++ .size __pxa210_proc_info, . - __pxa210_proc_info
++
++ .type __pxa250_proc_info,#object
++__pxa250_proc_info:
++ .long 0x69052100
++ .long 0xfffff7f0
++#if CACHE_WRITE_THROUGH
++ .long 0x00000c0a
++#else
++ .long 0x00000c0e
++#endif
++ b __xscale_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE
++ .long cpu_pxa250_info
++ .long xscale_processor_functions
++ .size __pxa250_proc_info, . - __pxa250_proc_info
++
++ .type __pxa255_proc_info,#object
++__pxa255_proc_info:
++ .long 0x69052d00
++ .long 0xfffffff0
++#if CACHE_WRITE_THROUGH
++ .long 0x00000c0a
++#else
++ .long 0x00000c0e
++#endif
++ b __xscale_setup
++ .long cpu_arch_name
++ .long cpu_elf_name
++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE
++ .long cpu_pxa255_info
++ .long xscale_processor_functions
++ .size __pxa255_proc_info, . - __pxa255_proc_info
++
+--- /dev/null
++++ linux-2.4.27/arch/arm/vmlinux-armv-xip.lds.in
+@@ -0,0 +1,125 @@
++/*
++ * ld script to make ARM Linux kernel
++ *
++ * (C) Copyright 2001 Lineo Japan, Inc.
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License. See linux/COPYING for more information.
++ *
++ * Based on arch/arm/vmlinux-armv.lds.in
++ *
++ * taken from the i386 version by Russell King
++ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
++ */
++OUTPUT_ARCH(arm)
++ENTRY(stext)
++SECTIONS
++{
++ . = TEXTADDR;
++ .init : { /* Init code and data */
++ _stext = .;
++ __init_begin = .;
++ *(.text.init)
++ __proc_info_begin = .;
++ *(.proc.info)
++ __proc_info_end = .;
++ __arch_info_begin = .;
++ *(.arch.info)
++ __arch_info_end = .;
++ __tagtable_begin = .;
++ *(.taglist)
++ __tagtable_end = .;
++ . = ALIGN(16);
++ __setup_start = .;
++ *(.setup.init)
++ __setup_end = .;
++ __initcall_start = .;
++ *(.initcall.init)
++ __initcall_end = .;
++ . = ALIGN(4096);
++ __init_end = .;
++ }
++
++ /DISCARD/ : { /* Exit code and data */
++ *(.text.exit)
++ *(.data.exit)
++ *(.exitcall.exit)
++ }
++
++ .text : { /* Real text segment */
++ _text = .; /* Text and read-only data */
++ *(.text)
++ *(.fixup)
++ *(.gnu.warning)
++ *(.text.lock) /* out-of-line lock text */
++ *(.rodata)
++ *(.rodata.*)
++ *(.glue_7)
++ *(.glue_7t)
++ *(.kstrtab)
++ *(.got) /* Global offset table */
++ *(.got.plt)
++
++ _etext = .; /* End of text section */
++ }
++
++ . = ALIGN(16);
++ __ex_table : { /* Exception table */
++ __start___ex_table = .;
++ *(__ex_table)
++ __stop___ex_table = .;
++ }
++
++ __ksymtab : { /* Kernel symbol table */
++ __start___ksymtab = .;
++ *(__ksymtab)
++ __stop___ksymtab = .;
++ }
++
++ _endtext = .;
++
++ . = DATAADDR;
++
++ _sdata = .;
++
++ . = ALIGN(8192);
++
++ .data : {
++ /*
++ * first, the init task union, aligned
++ * to an 8192 byte boundary.
++ */
++ *(.init.task)
++
++ /*
++ * then the cacheline aligned data
++ */
++ . = ALIGN(32);
++ *(.data.cacheline_aligned)
++
++ /*
++ * and the usual data section
++ */
++ *(.data)
++ CONSTRUCTORS
++
++ *(.data.init)
++
++ _edata = .;
++ }
++
++ .bss : {
++ __bss_start = .; /* BSS */
++ *(.bss)
++ *(COMMON)
++ _end = . ;
++ }
++ /* Stabs debugging sections. */
++ .stab 0 : { *(.stab) }
++ .stabstr 0 : { *(.stabstr) }
++ .stab.excl 0 : { *(.stab.excl) }
++ .stab.exclstr 0 : { *(.stab.exclstr) }
++ .stab.index 0 : { *(.stab.index) }
++ .stab.indexstr 0 : { *(.stab.indexstr) }
++ .comment 0 : { *(.comment) }
++}
+--- linux-2.4.27/drivers/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/Makefile
+@@ -25,6 +25,7 @@
+ subdir-$(CONFIG_NUBUS) += nubus
+ subdir-$(CONFIG_TC) += tc
+ subdir-$(CONFIG_VT) += video
++subdir-$(CONFIG_MMC) += mmc
+ subdir-$(CONFIG_MAC) += macintosh
+ subdir-$(CONFIG_PPC32) += macintosh
+ subdir-$(CONFIG_USB) += usb
+--- linux-2.4.27/drivers/char/Config.in~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/char/Config.in
+@@ -253,6 +253,7 @@
+ dep_tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG $CONFIG_FOOTBRIDGE
+ dep_tristate ' NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG $CONFIG_ARCH_NETWINDER
+ dep_tristate ' SA1100 watchdog' CONFIG_SA1100_WATCHDOG $CONFIG_ARCH_SA1100
++ dep_tristate ' PXA250/210 watchdog' CONFIG_SA1100_WATCHDOG $CONFIG_ARCH_PXA
+ dep_tristate ' EPXA watchdog' CONFIG_EPXA_WATCHDOG $CONFIG_ARCH_CAMELOT
+ dep_tristate ' Omaha watchdog' CONFIG_OMAHA_WATCHDOG $CONFIG_ARCH_OMAHA
+ dep_tristate ' AT91RM9200 watchdog' CONFIG_AT91_WATCHDOG $CONFIG_ARCH_AT91RM9200
+@@ -334,6 +335,9 @@
+ if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+ tristate 'SA1100 Real Time Clock' CONFIG_SA1100_RTC
+ fi
++if [ "$CONFIG_ARCH_PXA" = "y" ]; then
++ tristate 'PXA250/210 Real Time Clock' CONFIG_PXA_RTC
++fi
+ if [ "$CONFIG_ARCH_OMAHA" = "y" ]; then
+ tristate 'Omaha Real Time Clock' CONFIG_OMAHA_RTC
+ fi
+@@ -416,4 +420,8 @@
+ dep_tristate 'HP OB600 C/CT Pop-up mouse support' CONFIG_OBMOUSE $CONFIG_INPUT_MOUSEDEV
+ fi
+
++if [ "$CONFIG_ARCH_TRIZEPS2" = "y" ]; then
++ tristate ' MT6N TTL I/O suport' CONFIG_TRIZEPS2_TTLIO
++fi
++
+ endmenu
+--- linux-2.4.27/drivers/char/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/char/Makefile
+@@ -281,6 +281,7 @@
+ obj-$(CONFIG_MIPS_RTC) += mips_rtc.o
+ obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
+ obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o
++obj-$(CONFIG_PXA_RTC) += sa1100-rtc.o
+ obj-$(CONFIG_OMAHA_RTC) += omaha-rtc.o
+ ifeq ($(CONFIG_PPC),)
+ obj-$(CONFIG_NVRAM) += nvram.o
+--- /dev/null
++++ linux-2.4.27/drivers/char/mt6n_ttl.c
+@@ -0,0 +1,316 @@
++/*
++ * Trizeps-2 MT6N development board TTL-IO interface for Linux
++ *
++ * Copyright (C) 2003 Luc De Cock
++ *
++ * This driver allows use of the TTL-IO interface on the MT6N
++ * from user space. It exports the /dev/ttlio interface supporting
++ * some ioctl() and also the /proc/driver/ttlio pseudo-file
++ * for status information.
++ *
++ * The ioctls can be used to set individual TTL output lines.
++ * Only ioctls are supported.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Based on other minimal char device drivers, like Alan's
++ * watchdog, Ted's random, Paul's rtc, etc. etc.
++ *
++ * 1.00 Luc De Cock: initial version.
++ */
++
++#define TTLIO_VERSION "1.00"
++
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/miscdevice.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/proc_fs.h>
++
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++/* Writing to the register sets the output lines
++* Reading from the register returns the status of the input lines
++*/
++static unsigned short *ttlio_base = (unsigned short *) TRIZEPS2_TTLIO_BASE;
++static unsigned short ttlio_shadow = 0;
++
++/* interrupt stuff */
++static struct fasync_struct *ttlio_async_queue;
++static DECLARE_WAIT_QUEUE_HEAD(ttlio_wait);
++static int ttlio_irq_arrived = 0;
++static spinlock_t ttlio_lock;
++static unsigned short ttlio_in = 0;
++static volatile unsigned long teller = 0;
++
++
++static int ttlio_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg);
++
++static int ttlio_read_proc(char *page, char **start, off_t off,
++ int count, int *eof, void *data);
++
++
++static void ttlio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ ttlio_in = *ttlio_base;
++
++ ttlio_irq_arrived = 1;
++ teller++;
++
++ /* wake up the waiting process */
++ wake_up_interruptible(&ttlio_wait);
++ kill_fasync(&ttlio_async_queue, SIGIO, POLL_IN);
++}
++
++/*
++ * Now all the various file operations that we export.
++ */
++
++static int ttlio_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ unsigned long ttlio_val;
++
++ switch (cmd) {
++ case TTLIO_RESET: /* clear all lines */
++ {
++ *ttlio_base = 0;
++ return 0;
++ }
++ case TTLIO_GET: /* get state of TTL input lines */
++ {
++ ttlio_val = *ttlio_base;
++ return put_user(ttlio_val, (unsigned long *)arg);
++ }
++ case TTLIO_SET: /* set state of TTL output lines */
++ {
++ unsigned long user_val;
++ if (copy_from_user(&user_val, arg, sizeof(unsigned long)))
++ return -EFAULT;
++ ttlio_shadow |= (unsigned short) user_val;
++ *ttlio_base = ttlio_shadow;
++ return 0;
++ }
++ case TTLIO_UNSET: /* unset (clear) state of TTL output lines */
++ {
++ unsigned long user_val;
++ if (copy_from_user(&user_val, arg, sizeof(unsigned long)))
++ return -EFAULT;
++ ttlio_shadow &= ~((unsigned short) user_val);
++ *ttlio_base = ttlio_shadow;
++ return 0;
++ }
++ case 100: /* get counter */
++ {
++ return put_user(teller, (unsigned long *)arg);
++ }
++ case 101: /* reset counter */
++ {
++ teller = 0;
++ return 0;
++ }
++ default:
++ return -ENOTTY;
++ }
++ return 0;
++}
++
++static ssize_t ttlio_read(struct file *file, char *buf,
++ size_t count, loff_t *ppos)
++{
++ DECLARE_WAITQUEUE(wait, current);
++ unsigned short data;
++ ssize_t retval;
++
++ if (count < sizeof(unsigned short))
++ return -EINVAL;
++
++ if (file->f_flags & O_NONBLOCK) {
++ spin_lock_irq(&ttlio_lock);
++ data = *ttlio_base;
++ spin_unlock_irq(&ttlio_lock);
++ retval = put_user(data, (unsigned short *) buf);
++ if (!retval)
++ retval = sizeof(unsigned short);
++ return retval;
++ }
++ /* blocking read: wait for interrupt */
++ add_wait_queue(&ttlio_wait, &wait);
++ set_current_state(TASK_INTERRUPTIBLE);
++ for (;;) {
++ spin_lock_irq(&ttlio_lock);
++ data = *ttlio_base;
++ if (ttlio_irq_arrived) {
++ ttlio_irq_arrived = 0;
++ break;
++ }
++ spin_unlock_irq(&ttlio_lock);
++
++ if (signal_pending(current)) {
++ retval = -ERESTARTSYS;
++ goto out;
++ }
++ schedule();
++ }
++
++ spin_unlock_irq(&ttlio_lock);
++ retval = put_user(data, (unsigned short *)buf);
++ if (!retval)
++ retval = sizeof(unsigned short);
++
++out:
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&ttlio_wait, &wait);
++ return retval;
++}
++
++static ssize_t ttlio_write(struct file *file,
++ const char *buf, size_t count, loff_t *ppos)
++{
++ unsigned short content;
++
++ if (count < sizeof(unsigned short))
++ return -EINVAL;
++
++ if (copy_from_user (&content, buf, sizeof(unsigned short)))
++ return -EFAULT;
++
++ ttlio_shadow = content;
++ *ttlio_base = ttlio_shadow;
++
++ *ppos += sizeof(unsigned short);
++
++ return sizeof(unsigned short);
++}
++
++static int ttlio_open(struct inode *inode, struct file *file)
++{
++ ttlio_irq_arrived = 0;
++ return 0;
++}
++
++static int ttlio_fasync(int fd, struct file *filp, int on)
++{
++ return fasync_helper(fd, filp, on, &ttlio_async_queue);
++}
++
++static unsigned int ttlio_poll(struct file *file, poll_table *wait)
++{
++ poll_wait(file, &ttlio_wait, wait);
++ return ttlio_irq_arrived ? 0 : POLLIN | POLLRDNORM;
++}
++
++static loff_t ttlio_llseek(struct file *file, loff_t offset, int origin)
++{
++ return -ESPIPE;
++}
++
++/*
++ * The various file operations we support.
++ */
++
++static struct file_operations ttlio_fops = {
++ owner: THIS_MODULE,
++ llseek: ttlio_llseek,
++ read: ttlio_read,
++ poll: ttlio_poll,
++ write: ttlio_write,
++ ioctl: ttlio_ioctl,
++ open: ttlio_open,
++ fasync: ttlio_fasync,
++};
++
++static struct miscdevice ttlio_dev = {
++ TTLIO_MINOR,
++ "ttlio",
++ &ttlio_fops
++};
++
++static int __init ttlio_init(void)
++{
++ printk(KERN_INFO "MT6N TTL-I/O driver (release %s)\n",
++ TTLIO_VERSION);
++
++ misc_register(&ttlio_dev);
++ create_proc_read_entry ("driver/ttlio", 0, 0, ttlio_read_proc, NULL);
++
++ set_GPIO_IRQ_edge(GPIO_TTLIO_IRQ, GPIO_FALLING_EDGE);
++ if (request_irq(TTLIO_IRQ, ttlio_interrupt, SA_INTERRUPT, "ttlio irq", NULL)) {
++ printk(KERN_ERR "ttlio: irq %d already in use\n", TTLIO_IRQ);
++ return 1;
++ }
++ return 0;
++}
++
++static void __exit ttlio_exit(void)
++{
++ free_irq(TTLIO_IRQ, NULL);
++ remove_proc_entry ("driver/ttlio", NULL);
++ misc_deregister(&ttlio_dev);
++}
++
++module_init(ttlio_init);
++module_exit(ttlio_exit);
++EXPORT_NO_SYMBOLS;
++
++/*
++ * Info exported via "/proc/driver/ttlio".
++ */
++
++static int ttlio_proc_output(char *buf)
++{
++ char *p;
++ unsigned short val;
++ int i;
++
++ p = buf;
++
++ p += sprintf(p, "input : ");
++ /* write the state of the input lines */
++ val = *ttlio_base;
++ for (i = 0; i < 8*sizeof(unsigned short); i++) {
++ *p++ = (val & 1) ? '1' : '0';
++ val >>= 1;
++ }
++ *p = 0;
++ p += sprintf(p, "\noutput: ");
++ /* write the state of the output lines */
++ val = ttlio_shadow;
++ for (i = 0; i < 8*sizeof(unsigned short); i++) {
++ *p++ = (val & 1) ? '1' : '0';
++ val >>= 1;
++ }
++ *p = 0;
++ p += sprintf(p, "\n");
++
++ return p - buf;
++}
++
++static int ttlio_read_proc(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len = ttlio_proc_output (page);
++ if (len <= off+count) *eof = 1;
++ *start = page + off;
++ len -= off;
++ if (len > count) len = count;
++ if (len < 0) len = 0;
++ return len;
++}
++
++MODULE_AUTHOR("Luc De Cock");
++MODULE_DESCRIPTION("MT6N TTL-I/O driver");
++MODULE_LICENSE("GPL");
+--- linux-2.4.27/drivers/char/sa1100-rtc.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/char/sa1100-rtc.c
+@@ -1,5 +1,6 @@
+ /*
+ * Real Time Clock interface for Linux on StrongARM SA1100
++ * and XScale PXA250/210.
+ *
+ * Copyright (c) 2000 Nils Faerber
+ *
+@@ -470,5 +471,5 @@
+ module_exit(rtc_exit);
+
+ MODULE_AUTHOR("Nils Faerber <nils@@kernelconcepts.de>");
+-MODULE_DESCRIPTION("SA1100 Realtime Clock Driver (RTC)");
++MODULE_DESCRIPTION("SA1100/PXA Realtime Clock Driver (RTC)");
+ EXPORT_NO_SYMBOLS;
+--- linux-2.4.27/drivers/char/sa1100_wdt.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/char/sa1100_wdt.c
+@@ -1,5 +1,5 @@
+ /*
+- * Watchdog driver for the SA11x0
++ * Watchdog driver for the SA11x0/PXA
+ *
+ * (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
+ * Based on SoftDog driver by Alan Cox <alan@redhat.com>
+@@ -35,13 +35,20 @@
+
+ #define TIMER_MARGIN 60 /* (secs) Default is 1 minute */
+
+-static int sa1100_margin = TIMER_MARGIN; /* in seconds */
++static int timer_margin = TIMER_MARGIN; /* in seconds */
+ static int sa1100wdt_users;
+ static int pre_margin;
+ #ifdef MODULE
+-MODULE_PARM(sa1100_margin,"i");
++MODULE_PARM(timer_margin,"i");
+ #endif
+
++static void sa1100dog_ping( void)
++{
++ /* reload counter with (new) margin */
++ pre_margin=3686400 * timer_margin;
++ OSMR3 = OSCR + pre_margin;
++}
++
+ /*
+ * Allow only one person to hold it open
+ */
+@@ -51,9 +58,7 @@
+ if(test_and_set_bit(1,&sa1100wdt_users))
+ return -EBUSY;
+ MOD_INC_USE_COUNT;
+- /* Activate SA1100 Watchdog timer */
+- pre_margin=3686400 * sa1100_margin;
+- OSMR3 = OSCR + pre_margin;
++ sa1100dog_ping();
+ OSSR = OSSR_M3;
+ OWER = OWER_WME;
+ OIER |= OIER_E3;
+@@ -93,8 +98,11 @@
+ unsigned int cmd, unsigned long arg)
+ {
+ static struct watchdog_info ident = {
+- identity: "SA1100 Watchdog",
++ identity: "PXA/SA1100 Watchdog",
++ options: WDIOF_SETTIMEOUT,
++ firmware_version: 0,
+ };
++ int new_margin;
+
+ switch(cmd){
+ default:
+@@ -108,6 +116,16 @@
+ case WDIOC_KEEPALIVE:
+ OSMR3 = OSCR + pre_margin;
+ return 0;
++ case WDIOC_SETTIMEOUT:
++ if (get_user(new_margin, (int *)arg))
++ return -EFAULT;
++ if (new_margin < 1)
++ return -EINVAL;
++ timer_margin = new_margin;
++ sa1100dog_ping();
++ /* Fall */
++ case WDIOC_GETTIMEOUT:
++ return put_user(timer_margin, (int *)arg);
+ }
+ }
+
+@@ -123,7 +141,11 @@
+ static struct miscdevice sa1100dog_miscdev=
+ {
+ WATCHDOG_MINOR,
+- "SA1100 watchdog",
++#if defined(CONFIG_SA1100_WATCHDOG)
++ "SA1100_watchdog",
++#elif defined(CONFIG_PXA_WATCHDOG)
++ "PXA_watchdog",
++#endif
+ &sa1100dog_fops
+ };
+
+@@ -136,7 +158,7 @@
+ if (ret)
+ return ret;
+
+- printk("SA1100 Watchdog Timer: timer margin %d sec\n", sa1100_margin);
++ printk("SA1100/PXA Watchdog Timer: timer margin %d sec\n", timer_margin);
+
+ return 0;
+ }
+--- linux-2.4.27/drivers/char/serial.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/char/serial.c
+@@ -133,6 +133,16 @@
+ #endif
+ #endif
+
++#ifdef CONFIG_ARCH_PXA
++#define pxa_port(x) ((x) == PORT_PXA)
++#define pxa_buggy_port(x) ({ \
++ int cpu_ver; asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver)); \
++ ((x) == PORT_PXA && (cpu_ver & ~1) == 0x69052100); })
++#else
++#define pxa_port(x) (0)
++#define pxa_buggy_port(x) (0)
++#endif
++
+ /* Set of debugging defines */
+
+ #undef SERIAL_DEBUG_INTR
+@@ -311,6 +321,7 @@
+ { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
+ UART_STARTECH },
+ { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO },
++ { "PXA UART", 32, UART_CLEAR_FIFO | UART_USE_FIFO },
+ { 0, 0}
+ };
+
+@@ -424,6 +435,9 @@
+ case SERIAL_IO_MEM:
+ return readb((unsigned long) info->iomem_base +
+ (offset<<info->iomem_reg_shift));
++ case SERIAL_IO_MEM32:
++ return readl((unsigned long) info->iomem_base +
++ (offset<<info->iomem_reg_shift));
+ default:
+ return inb(info->port + offset);
+ }
+@@ -443,6 +457,10 @@
+ writeb(value, (unsigned long) info->iomem_base +
+ (offset<<info->iomem_reg_shift));
+ break;
++ case SERIAL_IO_MEM32:
++ writel(value, (unsigned long) info->iomem_base +
++ (offset<<info->iomem_reg_shift));
++ break;
+ default:
+ outb(value, info->port+offset);
+ }
+@@ -1306,6 +1324,16 @@
+ }
+ #endif
+
++#ifdef CONFIG_ARCH_PXA
++ if (state->type == PORT_PXA) {
++ switch ((long)state->iomem_base) {
++ case (long)&FFUART: CKEN |= CKEN6_FFUART; break;
++ case (long)&BTUART: CKEN |= CKEN7_BTUART; break;
++ case (long)&STUART: CKEN |= CKEN5_STUART; break;
++ }
++ }
++#endif
++
+ /*
+ * Clear the FIFO buffers and disable them
+ * (they will be reenabled in change_speed())
+@@ -1403,6 +1431,8 @@
+ {
+ if (state->irq != 0)
+ info->MCR |= UART_MCR_OUT2;
++ if (pxa_buggy_port(state->type) && state->irq != 0)
++ info->MCR ^= UART_MCR_OUT2;
+ }
+ info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
+ serial_outp(info, UART_MCR, info->MCR);
+@@ -1411,6 +1441,8 @@
+ * Finally, enable interrupts
+ */
+ info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
++ if (pxa_port(state->type))
++ info->IER |= UART_IER_UUE | UART_IER_RTOIE;
+ serial_outp(info, UART_IER, info->IER); /* enable interrupts */
+
+ #ifdef CONFIG_SERIAL_MANY_PORTS
+@@ -1542,6 +1574,8 @@
+ } else
+ #endif
+ info->MCR &= ~UART_MCR_OUT2;
++ if (pxa_buggy_port(state->type))
++ info->MCR ^= UART_MCR_OUT2;
+ info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
+
+ /* disable break condition */
+@@ -1567,6 +1601,20 @@
+ state->baud_base = SERIAL_RSA_BAUD_BASE_LO;
+ #endif
+
++#ifdef CONFIG_ARCH_PXA
++ if (state->type == PORT_PXA
++#ifdef CONFIG_SERIAL_CONSOLE
++ && sercons.index != info->line
++#endif
++ ) {
++ switch ((long)state->iomem_base) {
++ case (long)&FFUART: CKEN &= ~CKEN6_FFUART; break;
++ case (long)&BTUART: CKEN &= ~CKEN7_BTUART; break;
++ case (long)&STUART: CKEN &= ~CKEN5_STUART; break;
++ }
++ }
++#endif
++
+
+ (void)serial_in(info, UART_RX); /* read data port to reset things */
+
+@@ -1857,6 +1905,8 @@
+ save_flags(flags); cli();
+ info->IER |= UART_IER_THRI;
+ serial_out(info, UART_IER, info->IER);
++ if (pxa_buggy_port(info->state->type))
++ rs_interrupt_single(info->state->irq, NULL, NULL);
+ restore_flags(flags);
+ }
+
+@@ -1933,6 +1983,11 @@
+ && !(info->IER & UART_IER_THRI)) {
+ info->IER |= UART_IER_THRI;
+ serial_out(info, UART_IER, info->IER);
++ if (pxa_buggy_port(info->state->type)) {
++ save_flags(flags); cli();
++ rs_interrupt_single(info->state->irq, NULL, NULL);
++ restore_flags(flags);
++ }
+ }
+ return ret;
+ }
+@@ -1990,6 +2045,8 @@
+ /* Make sure transmit interrupts are on */
+ info->IER |= UART_IER_THRI;
+ serial_out(info, UART_IER, info->IER);
++ if (pxa_buggy_port(info->state->type))
++ rs_interrupt_single(info->state->irq, NULL, NULL);
+ }
+ }
+
+@@ -5517,7 +5574,6 @@
+ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+ state->magic = SSTATE_MAGIC;
+ state->line = i;
+- state->type = PORT_UNKNOWN;
+ state->custom_divisor = 0;
+ state->close_delay = 5*HZ/10;
+ state->closing_wait = 30*HZ;
+@@ -5531,14 +5587,18 @@
+ state->irq = irq_cannonicalize(state->irq);
+ if (state->hub6)
+ state->io_type = SERIAL_IO_HUB6;
+- if (state->port && check_region(state->port,8))
++ if (state->port && check_region(state->port,8)) {
++ state->type = PORT_UNKNOWN;
+ continue;
++ }
+ #ifdef CONFIG_MCA
+ if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus)
+ continue;
+ #endif
+- if (state->flags & ASYNC_BOOT_AUTOCONF)
++ if (state->flags & ASYNC_BOOT_AUTOCONF) {
++ state->type = PORT_UNKNOWN;
+ autoconfig(state);
++ }
+ }
+ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+ if (state->type == PORT_UNKNOWN)
+@@ -5858,6 +5918,8 @@
+ */
+ ier = serial_in(info, UART_IER);
+ serial_out(info, UART_IER, 0x00);
++ if (pxa_port(info->state->type))
++ serial_out(info, UART_IER, UART_IER_UUE);
+
+ /*
+ * Now, do each character
+@@ -6009,6 +6071,8 @@
+ serial_out(info, UART_DLM, quot >> 8); /* MS of divisor */
+ serial_out(info, UART_LCR, cval); /* reset DLAB */
+ serial_out(info, UART_IER, 0);
++ if (pxa_port(info->state->type))
++ serial_out(info, UART_IER, UART_IER_UUE);
+ serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+
+ /*
+--- linux-2.4.27/drivers/i2c/Config.in~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/i2c/Config.in
+@@ -54,6 +54,11 @@
+ fi
+ fi
+
++ if [ "$CONFIG_ARCH_PXA" = "y" ]; then
++ dep_tristate 'PXA I2C Algorithm' CONFIG_I2C_PXA_ALGO $CONFIG_I2C
++ dep_tristate 'PXA I2C Adapter' CONFIG_I2C_PXA_ADAP $CONFIG_I2C_PXA_ALGO
++ fi
++
+ if [ "$CONFIG_ALL_PPC" = "y" ] ; then
+ dep_tristate 'Keywest I2C interface in Apple Core99 machines' CONFIG_I2C_KEYWEST $CONFIG_I2C
+ fi
+--- linux-2.4.27/drivers/i2c/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/i2c/Makefile
+@@ -6,7 +6,7 @@
+
+ export-objs := i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \
+ i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \
+- i2c-proc.o
++ i2c-proc.o i2c-algo-pxa.o
+
+ # Init order: core, chardev, bit adapters, pcf adapters
+
+@@ -34,6 +34,10 @@
+ obj-$(CONFIG_I2C_ALGO_SIBYTE) += i2c-algo-sibyte.o i2c-sibyte.o
+ obj-$(CONFIG_I2C_MAX1617) += i2c-max1617.o
+ obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o
++# PXA adapters
++obj-$(CONFIG_I2C_PXA_ALGO) += i2c-algo-pxa.o
++obj-$(CONFIG_I2C_PXA_ADAP) += i2c-adap-pxa.o
++
+
+ # This is needed for automatic patch generation: sensors code starts here
+ # This is needed for automatic patch generation: sensors code ends here
+--- /dev/null
++++ linux-2.4.27/drivers/i2c/i2c-adap-pxa.c
+@@ -0,0 +1,396 @@
++/*
++ * i2c_adap_pxa.c
++ *
++ * I2C adapter for the PXA I2C bus access.
++ *
++ * Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * History:
++ * Apr 2002: Initial version [CS]
++ * Jun 2002: Properly seperated algo/adap [FB]
++ * Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem]
++ * Jan 2003: added limited signal handling [Kai-Uwe Bloem]
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <linux/i2c.h>
++#include <linux/i2c-id.h>
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/arch/irqs.h> /* for IRQ_I2C */
++
++#include "i2c-pxa.h"
++
++/*
++ * Set this to zero to remove all debug statements via dead code elimination.
++ */
++//#define DEBUG 1
++
++#if DEBUG
++static unsigned int i2c_debug = DEBUG;
++#else
++#define i2c_debug 0
++#endif
++
++static int irq = 0;
++static volatile int i2c_pending = 0; /* interrupt pending when 1 */
++static volatile int bus_error = 0;
++static volatile int tx_finished = 0;
++static volatile int rx_finished = 0;
++
++static wait_queue_head_t i2c_wait;
++static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte);
++
++/* place a byte in the transmit register */
++static void i2c_pxa_write_byte(u8 value)
++{
++ IDBR = value;
++}
++
++/* read byte in the receive register */
++static u8 i2c_pxa_read_byte(void)
++{
++ return (u8) (0xff & IDBR);
++}
++
++static void i2c_pxa_start(void)
++{
++ unsigned long icr = ICR;
++ icr |= ICR_START;
++ icr &= ~(ICR_STOP | ICR_ALDIE | ICR_ACKNAK);
++ ICR = icr;
++
++ bus_error=0; /* clear any bus_error from previous txfers */
++ tx_finished=0; /* clear rx and tx interrupts from previous txfers */
++ rx_finished=0;
++ i2c_pending = 0;
++}
++
++static void i2c_pxa_repeat_start(void)
++{
++ unsigned long icr = ICR;
++ icr |= ICR_START;
++ icr &= ~(ICR_STOP | ICR_ALDIE);
++ ICR = icr;
++
++ bus_error=0; /* clear any bus_error from previous txfers */
++ tx_finished=0; /* clear rx and tx interrupts from previous txfers */
++ rx_finished=0;
++ i2c_pending = 0;
++}
++
++static void i2c_pxa_stop(void)
++{
++ unsigned long icr = ICR;
++ icr |= ICR_STOP;
++ icr &= ~(ICR_START);
++ ICR = icr;
++}
++
++static void i2c_pxa_midbyte(void)
++{
++ unsigned long icr = ICR;
++ icr &= ~(ICR_START | ICR_STOP);
++ ICR = icr;
++}
++
++static void i2c_pxa_abort(void)
++{
++ unsigned long timeout = jiffies + HZ/4;
++
++#ifdef PXA_ABORT_MA
++ while ((long)(timeout - jiffies) > 0 && (ICR & ICR_TB)) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(1);
++ }
++
++ ICR |= ICR_MA;
++ udelay(100);
++#else
++ while ((long)(timeout - jiffies) > 0 && (IBMR & 0x1) == 0) {
++ i2c_pxa_transfer( 1, I2C_RECEIVE, 1);
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(1);
++ }
++#endif
++ ICR &= ~(ICR_MA | ICR_START | ICR_STOP);
++}
++
++static int i2c_pxa_wait_bus_not_busy( void)
++{
++ int timeout = DEF_TIMEOUT;
++
++ while (timeout-- && (ISR & ISR_IBB)) {
++ udelay(100); /* wait for 100 us */
++ }
++
++ return (timeout<=0);
++}
++
++static void i2c_pxa_wait_for_ite(void){
++ unsigned long flags;
++ if (irq > 0) {
++ save_flags_cli(flags);
++ if (i2c_pending == 0) {
++ interruptible_sleep_on_timeout(&i2c_wait, I2C_SLEEP_TIMEOUT );
++ }
++ i2c_pending = 0;
++ restore_flags(flags);
++ } else {
++ udelay(100);
++ }
++}
++
++static int i2c_pxa_wait_for_int( int wait_type)
++{
++ int timeout = DEF_TIMEOUT;
++#ifdef DEBUG
++ if (bus_error)
++ printk(KERN_INFO"i2c_pxa_wait_for_int: Bus error on enter\n");
++ if (rx_finished)
++ printk(KERN_INFO"i2c_pxa_wait_for_int: Receive interrupt on enter\n");
++ if (tx_finished)
++ printk(KERN_INFO"i2c_pxa_wait_for_int: Transmit interrupt on enter\n");
++#endif
++
++ if (wait_type == I2C_RECEIVE){ /* wait on receive */
++
++ do {
++ i2c_pxa_wait_for_ite();
++ } while (!(rx_finished) && timeout-- && !signal_pending(current));
++
++#ifdef DEBUG
++ if (timeout<0){
++ if (tx_finished)
++ printk("Error: i2c-algo-pxa.o: received a tx"
++ " interrupt while waiting on a rx in wait_for_int");
++ }
++#endif
++ } else { /* wait on transmit */
++
++ do {
++ i2c_pxa_wait_for_ite();
++ } while (!(tx_finished) && timeout-- && !signal_pending(current));
++
++#ifdef DEBUG
++ if (timeout<0){
++ if (rx_finished)
++ printk("Error: i2c-algo-pxa.o: received a rx"
++ " interrupt while waiting on a tx in wait_for_int");
++ }
++#endif
++ }
++
++ udelay(ACK_DELAY); /* this is needed for the bus error */
++
++ tx_finished=0;
++ rx_finished=0;
++
++ if (bus_error){
++ bus_error=0;
++ if( i2c_debug > 2)printk("wait_for_int: error - no ack.\n");
++ return BUS_ERROR;
++ }
++
++ if (signal_pending(current)) {
++ return (-ERESTARTSYS);
++ } else if (timeout < 0) {
++ if( i2c_debug > 2)printk("wait_for_int: timeout.\n");
++ return(-EIO);
++ } else
++ return(0);
++}
++
++static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte)
++{
++ if( lastbyte)
++ {
++ if( receive==I2C_RECEIVE) ICR |= ICR_ACKNAK;
++ i2c_pxa_stop();
++ }
++ else if( midbyte)
++ {
++ i2c_pxa_midbyte();
++ }
++ ICR |= ICR_TB;
++}
++
++static void i2c_pxa_reset( void)
++{
++#ifdef DEBUG
++ printk("Resetting I2C Controller Unit\n");
++#endif
++
++ /* abort any transfer currently under way */
++ i2c_pxa_abort();
++
++ /* reset according to 9.8 */
++ ICR = ICR_UR;
++ ISR = I2C_ISR_INIT;
++ ICR &= ~ICR_UR;
++
++ /* set the global I2C clock on */
++ CKEN |= CKEN14_I2C;
++
++ /* set our slave address */
++ ISAR = I2C_PXA_SLAVE_ADDR;
++
++ /* set control register values */
++ ICR = I2C_ICR_INIT;
++
++ /* clear any leftover states from prior transmissions */
++ i2c_pending = rx_finished = tx_finished = bus_error = 0;
++
++ /* enable unit */
++ ICR |= ICR_IUE;
++ udelay(100);
++}
++
++static void i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs)
++{
++ int status, wakeup = 0;
++ status = (ISR);
++
++ if (status & ISR_BED){
++ (ISR) |= ISR_BED;
++ bus_error=ISR_BED;
++ wakeup = 1;
++ }
++ if (status & ISR_ITE){
++ (ISR) |= ISR_ITE;
++ tx_finished=ISR_ITE;
++ wakeup = 1;
++ }
++ if (status & ISR_IRF){
++ (ISR) |= ISR_IRF;
++ rx_finished=ISR_IRF;
++ wakeup = 1;
++ }
++ if (wakeup) {
++ i2c_pending = 1;
++ wake_up_interruptible(&i2c_wait);
++ }
++}
++
++static int i2c_pxa_resource_init( void)
++{
++ init_waitqueue_head(&i2c_wait);
++
++ if (request_irq(IRQ_I2C, &i2c_pxa_handler, SA_INTERRUPT, "I2C_PXA", 0) < 0) {
++ irq = 0;
++ if( i2c_debug)
++ printk(KERN_INFO "I2C: Failed to register I2C irq %i\n", IRQ_I2C);
++ return -ENODEV;
++ }else{
++ irq = IRQ_I2C;
++ enable_irq(irq);
++ }
++ return 0;
++}
++
++static void i2c_pxa_resource_release( void)
++{
++ if( irq > 0)
++ {
++ disable_irq(irq);
++ free_irq(irq,0);
++ irq=0;
++ }
++}
++
++static void i2c_pxa_inc_use(struct i2c_adapter *adap)
++{
++#ifdef MODULE
++ MOD_INC_USE_COUNT;
++#endif
++}
++
++static void i2c_pxa_dec_use(struct i2c_adapter *adap)
++{
++#ifdef MODULE
++ MOD_DEC_USE_COUNT;
++#endif
++}
++
++static int i2c_pxa_client_register(struct i2c_client *client)
++{
++ return 0;
++}
++
++static int i2c_pxa_client_unregister(struct i2c_client *client)
++{
++ return 0;
++}
++
++static struct i2c_algo_pxa_data i2c_pxa_data = {
++ write_byte: i2c_pxa_write_byte,
++ read_byte: i2c_pxa_read_byte,
++
++ start: i2c_pxa_start,
++ repeat_start: i2c_pxa_repeat_start,
++ stop: i2c_pxa_stop,
++ abort: i2c_pxa_abort,
++
++ wait_bus_not_busy: i2c_pxa_wait_bus_not_busy,
++ wait_for_interrupt: i2c_pxa_wait_for_int,
++ transfer: i2c_pxa_transfer,
++ reset: i2c_pxa_reset,
++
++ udelay: 10,
++ timeout: DEF_TIMEOUT,
++};
++
++static struct i2c_adapter i2c_pxa_ops = {
++ name: "PXA-I2C-Adapter",
++ id: I2C_ALGO_PXA,
++ algo_data: &i2c_pxa_data,
++ inc_use: i2c_pxa_inc_use,
++ dec_use: i2c_pxa_dec_use,
++ client_register: i2c_pxa_client_register,
++ client_unregister: i2c_pxa_client_unregister,
++ retries: 2,
++};
++
++extern int i2c_pxa_add_bus(struct i2c_adapter *);
++extern int i2c_pxa_del_bus(struct i2c_adapter *);
++
++static int __init i2c_adap_pxa_init(void)
++{
++ if( i2c_pxa_resource_init() == 0) {
++
++ if (i2c_pxa_add_bus(&i2c_pxa_ops) < 0) {
++ i2c_pxa_resource_release();
++ printk(KERN_INFO "I2C: Failed to add bus\n");
++ return -ENODEV;
++ }
++ } else {
++ return -ENODEV;
++ }
++
++ printk(KERN_INFO "I2C: Successfully added bus\n");
++
++ return 0;
++}
++
++static void i2c_adap_pxa_exit(void)
++{
++ i2c_pxa_del_bus( &i2c_pxa_ops);
++ i2c_pxa_resource_release();
++
++ printk(KERN_INFO "I2C: Successfully removed bus\n");
++}
++
++module_init(i2c_adap_pxa_init);
++module_exit(i2c_adap_pxa_exit);
+--- /dev/null
++++ linux-2.4.27/drivers/i2c/i2c-algo-pxa.c
+@@ -0,0 +1,376 @@
++/*
++ * i2c-algo-pxa.c
++ *
++ * I2C algorithm for the PXA I2C bus access.
++ * Byte driven algorithm similar to pcf.
++ *
++ * Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * History:
++ * Apr 2002: Initial version [CS]
++ * Jun 2002: Properly seperated algo/adap [FB]
++ * Jan 2003: added limited signal handling [Kai-Uwe Bloem]
++ * Jan 2003: allow SMBUS_QUICK as valid msg [FB]
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/i2c.h> /* struct i2c_msg and others */
++#include <linux/i2c-id.h>
++
++#include "i2c-pxa.h"
++
++/*
++ * Set this to zero to remove all the debug statements via dead code elimination.
++ */
++//#define DEBUG 1
++
++#if DEBUG
++static unsigned int i2c_debug = DEBUG;
++#else
++#define i2c_debug 0
++#endif
++
++static int pxa_scan = 1;
++
++static int i2c_pxa_valid_messages( struct i2c_msg msgs[], int num)
++{
++ int i;
++ if (num < 1 || num > MAX_MESSAGES){
++ if( i2c_debug)
++ printk(KERN_INFO "Invalid number of messages (max=%d, num=%d)\n",
++ MAX_MESSAGES, num);
++ return -EINVAL;
++ }
++
++ /* check consistency of our messages */
++ for (i=0;i<num;i++){
++ if (&msgs[i]==NULL){
++ if( i2c_debug) printk(KERN_INFO "Msgs is NULL\n");
++ return -EINVAL;
++ } else {
++ if (msgs[i].len < 0 || msgs[i].buf == NULL){
++ if( i2c_debug)printk(KERN_INFO "Length is less than zero");
++ return -EINVAL;
++ }
++ }
++ }
++
++ return 1;
++}
++
++static int i2c_pxa_readbytes(struct i2c_adapter *i2c_adap, char *buf,
++ int count, int last)
++{
++
++ int i, timeout=0;
++ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
++
++ /* increment number of bytes to read by one -- read dummy byte */
++ for (i = 0; i <= count; i++) {
++ if (i!=0){
++ /* set ACK to NAK for last received byte ICR[ACKNAK] = 1
++ only if not a repeated start */
++
++ if ((i == count) && last) {
++ adap->transfer( last, I2C_RECEIVE, 0);
++ }else{
++ adap->transfer( 0, I2C_RECEIVE, 1);
++ }
++
++ timeout = adap->wait_for_interrupt(I2C_RECEIVE);
++
++#ifdef DEBUG
++ if (timeout==BUS_ERROR){
++ printk(KERN_INFO "i2c_pxa_readbytes: bus error -> forcing reset\n");
++ adap->reset();
++ return I2C_RETRY;
++ } else
++#endif
++ if (timeout == -ERESTARTSYS) {
++ adap->abort();
++ return timeout;
++ } else
++ if (timeout){
++#ifdef DEBUG
++ printk(KERN_INFO "i2c_pxa_readbytes: timeout -> forcing reset\n");
++#endif
++ adap->reset();
++ return I2C_RETRY;
++ }
++
++ }
++
++ if (i) {
++ buf[i - 1] = adap->read_byte();
++ } else {
++ adap->read_byte(); /* dummy read */
++ }
++ }
++ return (i - 1);
++}
++
++static int i2c_pxa_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
++ int count, int last)
++{
++
++ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
++ int wrcount, timeout;
++
++ for (wrcount=0; wrcount<count; ++wrcount) {
++
++ adap->write_byte(buf[wrcount]);
++ if ((wrcount==(count-1)) && last) {
++ adap->transfer( last, I2C_TRANSMIT, 0);
++ }else{
++ adap->transfer( 0, I2C_TRANSMIT, 1);
++ }
++
++ timeout = adap->wait_for_interrupt(I2C_TRANSMIT);
++
++#ifdef DEBUG
++ if (timeout==BUS_ERROR) {
++ printk(KERN_INFO "i2c_pxa_sendbytes: bus error -> forcing reset.\n");
++ adap->reset();
++ return I2C_RETRY;
++ } else
++#endif
++ if (timeout == -ERESTARTSYS) {
++ adap->abort();
++ return timeout;
++ } else
++ if (timeout) {
++#ifdef DEBUG
++ printk(KERN_INFO "i2c_pxa_sendbytes: timeout -> forcing reset\n");
++#endif
++ adap->reset();
++ return I2C_RETRY;
++ }
++ }
++ return (wrcount);
++}
++
++
++static inline int i2c_pxa_set_ctrl_byte(struct i2c_algo_pxa_data * adap, struct i2c_msg *msg)
++{
++ u16 flags = msg->flags;
++ u8 addr;
++ addr = (u8) ( (0x7f & msg->addr) << 1 );
++ if (flags & I2C_M_RD )
++ addr |= 1;
++ if (flags & I2C_M_REV_DIR_ADDR )
++ addr ^= 1;
++ adap->write_byte(addr);
++ return 0;
++}
++
++static int i2c_pxa_do_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
++{
++ struct i2c_algo_pxa_data * adap;
++ struct i2c_msg *pmsg=NULL;
++ int i;
++ int ret=0, timeout;
++
++ adap = i2c_adap->algo_data;
++
++ timeout = adap->wait_bus_not_busy();
++
++ if (timeout) {
++ return I2C_RETRY;
++ }
++
++ for (i = 0;ret >= 0 && i < num; i++) {
++ int last = i + 1 == num;
++ pmsg = &msgs[i];
++
++ ret = i2c_pxa_set_ctrl_byte(adap,pmsg);
++
++ /* Send START */
++ if (i == 0) {
++ adap->start();
++ }else{
++ adap->repeat_start();
++ }
++
++ adap->transfer(0, I2C_TRANSMIT, 0);
++
++ /* Wait for ITE (transmit empty) */
++ timeout = adap->wait_for_interrupt(I2C_TRANSMIT);
++
++#ifdef DEBUG
++ /* Check for ACK (bus error) */
++ if (timeout==BUS_ERROR){
++ printk(KERN_INFO "i2c_pxa_do_xfer: bus error -> forcing reset\n");
++ adap->reset();
++ return I2C_RETRY;
++ } else
++#endif
++ if (timeout == -ERESTARTSYS) {
++ adap->abort();
++ return timeout;
++ } else
++ if (timeout) {
++#ifdef DEBUG
++ printk(KERN_INFO "i2c_pxa_do_xfer: timeout -> forcing reset\n");
++#endif
++ adap->reset();
++ return I2C_RETRY;
++ }
++/* FIXME: handle arbitration... */
++#if 0
++ /* Check for bus arbitration loss */
++ if (adap->arbitration_loss()){
++ printk("Arbitration loss detected \n");
++ adap->reset();
++ return I2C_RETRY;
++ }
++#endif
++
++ /* Read */
++ if (pmsg->flags & I2C_M_RD) {
++ /* read bytes into buffer*/
++ ret = i2c_pxa_readbytes(i2c_adap, pmsg->buf, pmsg->len, last);
++#if DEBUG > 2
++ if (ret != pmsg->len) {
++ printk(KERN_INFO"i2c_pxa_do_xfer: read %d/%d bytes.\n",
++ ret, pmsg->len);
++ } else {
++ printk(KERN_INFO"i2c_pxa_do_xfer: read %d bytes.\n",ret);
++ }
++#endif
++ } else { /* Write */
++ ret = i2c_pxa_sendbytes(i2c_adap, pmsg->buf, pmsg->len, last);
++#if DEBUG > 2
++ if (ret != pmsg->len) {
++ printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d/%d bytes.\n",
++ ret, pmsg->len);
++ } else {
++ printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d bytes.\n",ret);
++ }
++#endif
++ }
++ }
++
++ if (ret<0){
++ return ret;
++ }else{
++ return i;
++ }
++}
++
++static int i2c_pxa_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
++{
++ int retval = i2c_pxa_valid_messages( msgs, num);
++ if( retval > 0)
++ {
++ int i;
++ for (i=i2c_adap->retries; i>=0; i--){
++ int retval = i2c_pxa_do_xfer(i2c_adap,msgs,num);
++ if (retval!=I2C_RETRY){
++ return retval;
++ }
++ if( i2c_debug)printk(KERN_INFO"Retrying transmission \n");
++ udelay(100);
++ }
++ if( i2c_debug)printk(KERN_INFO"Retried %i times\n",i2c_adap->retries);
++ return -EREMOTEIO;
++
++ }
++ return retval;
++}
++
++struct i2c_algorithm i2c_pxa_algorithm = {
++ name: "PXA-I2C-Algorithm",
++ id: I2C_ALGO_PXA,
++ master_xfer: i2c_pxa_xfer,
++ smbus_xfer: NULL,
++ slave_send: NULL,
++ slave_recv: NULL,
++ algo_control: NULL,
++};
++
++/*
++ * registering functions to load algorithms at runtime
++ */
++int i2c_pxa_add_bus(struct i2c_adapter *i2c_adap)
++{
++ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
++
++ printk(KERN_INFO"I2C: Adding %s.\n", i2c_adap->name);
++
++ i2c_adap->algo = &i2c_pxa_algorithm;
++
++ MOD_INC_USE_COUNT;
++
++ /* register new adapter to i2c module... */
++ i2c_add_adapter(i2c_adap);
++
++ adap->reset();
++
++ /* scan bus */
++ if (pxa_scan) {
++ int i;
++ printk(KERN_INFO "I2C: Scanning bus ");
++ for (i = 0x02; i < 0xff; i+=2) {
++ if( i==(I2C_PXA_SLAVE_ADDR<<1)) continue;
++
++ if (adap->wait_bus_not_busy()) {
++ printk(KERN_INFO "I2C: scanning bus %s - TIMEOUTed.\n",
++ i2c_adap->name);
++ return -EIO;
++ }
++ adap->write_byte(i);
++ adap->start();
++ adap->transfer(0, I2C_TRANSMIT, 0);
++
++ if ((adap->wait_for_interrupt(I2C_TRANSMIT) != BUS_ERROR)) {
++ printk("(%02x)",i>>1);
++ adap->abort();
++ } else {
++// printk(".");
++ adap->stop();
++ }
++ udelay(adap->udelay);
++ }
++ printk("\n");
++ }
++ return 0;
++}
++
++int i2c_pxa_del_bus(struct i2c_adapter *i2c_adap)
++{
++ int res;
++ if ((res = i2c_del_adapter(i2c_adap)) < 0)
++ return res;
++
++ MOD_DEC_USE_COUNT;
++
++ printk(KERN_INFO "I2C: Removing %s.\n", i2c_adap->name);
++
++ return 0;
++}
++
++static int __init i2c_algo_pxa_init (void)
++{
++ printk(KERN_INFO "I2C: PXA algorithm module loaded.\n");
++ return 0;
++}
++
++EXPORT_SYMBOL(i2c_pxa_add_bus);
++EXPORT_SYMBOL(i2c_pxa_del_bus);
++
++MODULE_PARM(pxa_scan, "i");
++MODULE_PARM_DESC(pxa_scan, "Scan for active chips on the bus");
++
++MODULE_AUTHOR("Intrinsyc Software Inc.");
++MODULE_LICENSE("GPL");
++
++module_init(i2c_algo_pxa_init);
+--- /dev/null
++++ linux-2.4.27/drivers/i2c/i2c-pxa.h
+@@ -0,0 +1,76 @@
++/*
++ * i2c_pxa.h
++ *
++ * Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++#ifndef _I2C_PXA_H_
++#define _I2C_PXA_H_
++
++struct i2c_algo_pxa_data
++{
++ void (*write_byte) (u8 value);
++ u8 (*read_byte) (void);
++ void (*start) (void);
++ void (*repeat_start) (void);
++ void (*stop) (void);
++ void (*abort) (void);
++ int (*wait_bus_not_busy) (void);
++ int (*wait_for_interrupt) (int wait_type);
++ void (*transfer) (int lastbyte, int receive, int midbyte);
++ void (*reset) (void);
++
++ int udelay;
++ int timeout;
++};
++
++#define DEF_TIMEOUT 3
++#define BUS_ERROR (-EREMOTEIO)
++#define ACK_DELAY 0 /* time to delay before checking bus error */
++#define MAX_MESSAGES 65536 /* maximum number of messages to send */
++
++#define I2C_SLEEP_TIMEOUT 2 /* time to sleep for on i2c transactions */
++#define I2C_RETRY (-2000) /* an error has occurred retry transmit */
++#define I2C_TRANSMIT 1
++#define I2C_RECEIVE 0
++#define I2C_PXA_SLAVE_ADDR 0x1 /* slave pxa unit address */
++#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) /* ICR initialization value */
++/* ICR initialize bit values
++*
++* 15. FM 0 (100 Khz operation)
++* 14. UR 0 (No unit reset)
++* 13. SADIE 0 (Disables the unit from interrupting on slave addresses
++* matching its slave address)
++* 12. ALDIE 0 (Disables the unit from interrupt when it loses arbitration
++* in master mode)
++* 11. SSDIE 0 (Disables interrupts from a slave stop detected, in slave mode)
++* 10. BEIE 1 (Enable interrupts from detected bus errors, no ACK sent)
++* 9. IRFIE 1 (Enable interrupts from full buffer received)
++* 8. ITEIE 1 (Enables the I2C unit to interrupt when transmit buffer empty)
++* 7. GCD 1 (Disables i2c unit response to general call messages as a slave)
++* 6. IUE 0 (Disable unit until we change settings)
++* 5. SCLE 1 (Enables the i2c clock output for master mode (drives SCL)
++* 4. MA 0 (Only send stop with the ICR stop bit)
++* 3. TB 0 (We are not transmitting a byte initially)
++* 2. ACKNAK 0 (Send an ACK after the unit receives a byte)
++* 1. STOP 0 (Do not send a STOP)
++* 0. START 0 (Do not send a START)
++*
++*/
++
++#define I2C_ISR_INIT 0x7FF /* status register init */
++/* I2C status register init values
++ *
++ * 10. BED 1 (Clear bus error detected)
++ * 9. SAD 1 (Clear slave address detected)
++ * 7. IRF 1 (Clear IDBR Receive Full)
++ * 6. ITE 1 (Clear IDBR Transmit Empty)
++ * 5. ALD 1 (Clear Arbitration Loss Detected)
++ * 4. SSD 1 (Clear Slave Stop Detected)
++ */
++
++#endif
+--- linux-2.4.27/drivers/misc/Config.in~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/misc/Config.in
+@@ -13,5 +13,6 @@
+ dep_tristate 'Support for UCB1200 / UCB1300' CONFIG_MCP_UCB1200 $CONFIG_MCP
+ dep_tristate ' Audio / Telephony interface support' CONFIG_MCP_UCB1200_AUDIO $CONFIG_MCP_UCB1200 $CONFIG_SOUND
+ dep_tristate ' Touchscreen interface support' CONFIG_MCP_UCB1200_TS $CONFIG_MCP_UCB1200
++dep_tristate ' UCB1400 Touchscreen support' CONFIG_MCP_UCB1400_TS $CONFIG_ARCH_PXA $CONFIG_SOUND
+
+ endmenu
+--- linux-2.4.27/drivers/misc/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/misc/Makefile
+@@ -11,13 +11,15 @@
+
+ O_TARGET := misc.o
+
+-export-objs := mcp-core.o mcp-sa1100.o ucb1x00-core.o
++export-objs := mcp-core.o mcp-sa1100.o mcp-pxa.o \
++ ucb1x00-core.o
+
+-obj-$(CONFIG_MCP) += mcp-core.o
+-obj-$(CONFIG_MCP_SA1100) += mcp-sa1100.o
++obj-$(CONFIG_MCP_SA1100) += mcp-core.o mcp-sa1100.o
+ obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
+ obj-$(CONFIG_MCP_UCB1200_AUDIO) += ucb1x00-audio.o
+ obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o
++obj-$(CONFIG_MCP_UCB1400_TS) += mcp-pxa.o ucb1x00-core.o ucb1x00-ts.o
++obj-$(CONFIG_PXA_CERF_PDA) += cerf_ucb1400gpio.o
+
+ include $(TOPDIR)/Rules.make
+
+--- /dev/null
++++ linux-2.4.27/drivers/misc/cerf_ucb1400gpio.c
+@@ -0,0 +1,189 @@
++/*
++ * cerf_ucb1400gpio.c
++ *
++ * UCB1400 GPIO control stuff for the cerf.
++ *
++ * Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * History:
++ * Mar 2002: Initial version [FB]
++ * Jun 2002: Removed ac97 dependency [FB]
++ *
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++
++#include "ucb1x00.h"
++
++/*
++ * Set this to zero to remove all the debug statements via
++ * dead code elimination.
++ */
++#define DEBUGGING 0
++
++#if DEBUGGING
++static unsigned int ucb_debug = DEBUGGING;
++#else
++#define ucb_debug 0
++#endif
++
++#define UP 1
++#define DOWN 0
++
++/* -- -- */
++
++void cerf_ucb1400gpio_lcd_enable( void)
++{
++ struct ucb1x00 * ucb = ucb1x00_get();
++ if( ucb_debug > 2) printk( KERN_INFO "Enabling LCD.\n");
++ /* Enable [not] LCD_RESET to enable the LCD display */
++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_LCD_RESET);
++ ucb1x00_io_write( ucb, UCB1400_GPIO_LCD_RESET, 0);
++
++ /* Enable the Contrast circuit */
++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_CONT_ENA);
++ ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_ENA, 0);
++}
++
++void cerf_ucb1400gpio_lcd_disable( void)
++{
++ struct ucb1x00 * ucb = ucb1x00_get();
++ if( ucb_debug > 2) printk( KERN_INFO "Disabling LCD.\n");
++ /* Disable the Contrast circuit */
++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_CONT_ENA);
++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_ENA);
++
++ /* Disable [not] LCD_RESET to enable the LCD display */
++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_LCD_RESET);
++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_LCD_RESET);
++}
++
++void cerf_ucb1400gpio_lcd_contrast_step( int direction)
++{
++ struct ucb1x00 * ucb = ucb1x00_get();
++ // Assert the chip select and the up modifier
++ ucb1x00_io_set_dir( ucb, 0,
++ (UCB1400_GPIO_CONT_CS |
++ UCB1400_GPIO_CONT_DOWN |
++ UCB1400_GPIO_CONT_INC));
++
++ if( direction == DOWN)
++ {
++ if( ucb_debug > 3)
++ printk(KERN_INFO "cerf_ucb1400gpio_lcd_contrast_step: "
++ "stepping up\n");
++ //goin' up
++ ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_DOWN, 0);
++ }
++ else
++ {
++ if( ucb_debug > 3)
++ printk(KERN_INFO "cerf_ucb1400gpio_lcd_contrast_step: "
++ "stepping down\n");
++ //goin' down
++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_DOWN);
++ }
++
++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_CS);
++
++ // Assert the line up, down then up again
++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_INC);
++ udelay(1);
++ ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_INC, 0);
++ udelay(1);
++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_INC);
++
++ // Deassert the chip select and the up modifier
++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_DOWN);
++ ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_CS, 0);
++}
++
++/* -- -- */
++
++void cerf_ucb1400gpio_irda_enable( void)
++{
++ struct ucb1x00 * ucb = ucb1x00_get();
++ printk( KERN_INFO "Enabling IRDA.\n");
++ /* Enable IRDA (active low) */
++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_IRDA_ENABLE);
++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_IRDA_ENABLE);
++}
++
++void cerf_ucb1400gpio_irda_disable( void)
++{
++ struct ucb1x00 * ucb = ucb1x00_get();
++ printk( KERN_INFO "Disabling IRDA.\n");
++ /* Disable IRDA (active low) */
++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_IRDA_ENABLE);
++ ucb1x00_io_write( ucb, UCB1400_GPIO_IRDA_ENABLE, 0);
++}
++
++/* -- -- */
++
++void cerf_ucb1400gpio_bt_enable( void)
++{
++ struct ucb1x00 * ucb = ucb1x00_get();
++ printk( KERN_INFO "Enabling Bluetooth.\n");
++ /* Enable BT (active low) */
++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_BT_ENABLE);
++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_BT_ENABLE);
++}
++
++void cerf_ucb1400gpio_bt_disable( void)
++{
++ struct ucb1x00 * ucb = ucb1x00_get();
++ printk( KERN_INFO "Disabling Bluetooth.\n");
++ /* Disable BT (active low) */
++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_BT_ENABLE);
++ ucb1x00_io_write( ucb, UCB1400_GPIO_BT_ENABLE, 0);
++}
++
++/* -- -- */
++
++/* -- Enable Bluetooth and IRDA automatically via pseudo module -- */
++#if defined(CONFIG_BLUEZ) || defined(CONFIG_IRDA)
++static int __init cerf_ucb1400gpio_module_init (void)
++{
++#ifdef CONFIG_BLUEZ
++ cerf_ucb1400gpio_bt_enable();
++#endif
++
++#ifdef CONFIG_IRDA
++ cerf_ucb1400gpio_irda_enable();
++#endif
++ return 0;
++}
++
++static void __exit cerf_ucb1400gpio_module_exit (void)
++{
++#ifdef CONFIG_BLUEZ
++ cerf_ucb1400gpio_bt_disable();
++#endif
++
++#ifdef CONFIG_IRDA
++ cerf_ucb1400gpio_irda_disable();
++#endif
++}
++
++module_init(cerf_ucb1400gpio_module_init);
++module_exit(cerf_ucb1400gpio_module_exit);
++#endif
++
+--- /dev/null
++++ linux-2.4.27/drivers/misc/mcp-pxa.c
+@@ -0,0 +1,57 @@
++/*
++ * linux/drivers/misc/mcp-pxa.c
++ *
++ * 2002-01-10 Jeff Sutherland <jeffs@accelent.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ * NOTE: This is a quick hack to gain access to the aclink codec's
++ * touch screen facility. Its audio is handled by a separate
++ * (non-mcp) driver at the present time.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/ac97_codec.h>
++
++#include "mcp.h"
++
++
++extern int pxa_ac97_get(struct ac97_codec **codec);
++extern void pxa_ac97_put(void);
++
++
++struct mcp *mcp_get(void)
++{
++ struct ac97_codec *codec;
++ if (pxa_ac97_get(&codec) < 0)
++ return NULL;
++ return (struct mcp *)codec;
++}
++
++void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val)
++{
++ struct ac97_codec *codec = (struct ac97_codec *)mcp;
++ codec->codec_write(codec, reg, val);
++}
++
++unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg)
++{
++ struct ac97_codec *codec = (struct ac97_codec *)mcp;
++ return codec->codec_read(codec, reg);
++}
++
++void mcp_enable(struct mcp *mcp)
++{
++ /*
++ * Should we do something here to make sure the aclink
++ * codec is alive???
++ * A: not for now --NP
++ */
++}
++
++void mcp_disable(struct mcp *mcp)
++{
++}
+--- linux-2.4.27/drivers/misc/mcp.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/misc/mcp.h
+@@ -10,16 +10,22 @@
+ #ifndef MCP_H
+ #define MCP_H
+
++#ifdef CONFIG_ARCH_SA1100
++#include <asm/dma.h>
++#endif
++
+ struct mcp {
+ struct module *owner;
+ spinlock_t lock;
+ int use_count;
+ unsigned int sclk_rate;
+ unsigned int rw_timeout;
++#ifdef CONFIG_ARCH_SA1100
+ dma_device_t dma_audio_rd;
+ dma_device_t dma_audio_wr;
+ dma_device_t dma_telco_rd;
+ dma_device_t dma_telco_wr;
++#endif
+ void (*set_telecom_divisor)(struct mcp *, unsigned int);
+ void (*set_audio_divisor)(struct mcp *, unsigned int);
+ void (*reg_write)(struct mcp *, unsigned int, unsigned int);
+--- linux-2.4.27/drivers/misc/ucb1x00-core.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/misc/ucb1x00-core.c
+@@ -23,12 +23,18 @@
+ #include <linux/errno.h>
+ #include <linux/interrupt.h>
+ #include <linux/pm.h>
++#include <linux/tqueue.h>
++#include <linux/config.h>
+
+-#include <asm/dma.h>
+-#include <asm/hardware.h>
+ #include <asm/irq.h>
+ #include <asm/mach-types.h>
++
++#ifdef CONFIG_ARCH_SA1100
++#include <asm/arch/assabet.h>
+ #include <asm/arch/shannon.h>
++#endif
++
++#include <asm/hardware.h>
+
+ #include "ucb1x00.h"
+
+@@ -155,6 +161,10 @@
+ *
+ * If called for a synchronised ADC conversion, it may sleep
+ * with the ADC semaphore held.
++ *
++ * See ucb1x00.h for definition of the UCB_ADC_DAT macro. It
++ * addresses a bug in the ucb1200/1300 which, of course, Philips
++ * decided to finally fix in the ucb1400 ;-) -jws
+ */
+ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
+ {
+@@ -218,22 +228,75 @@
+ * Since we need to read an internal register, we must re-enable
+ * SIBCLK to talk to the chip. We leave the clock running until
+ * we have finished processing all interrupts from the chip.
++ *
++ * A restriction with interrupts exists when using the ucb1400, as
++ * the codec read/write routines may sleep while waiting for codec
++ * access completion and uses semaphores for access control to the
++ * AC97 bus. A complete codec read cycle could take anywhere from
++ * 60 to 100uSec so we *definitely* don't want to spin inside the
++ * interrupt handler waiting for codec access. So, we handle the
++ * interrupt by scheduling a RT kernel thread to run in process
++ * context instead of interrupt context.
+ */
+-static void ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs)
++
++static int ucb1x00_thread(void *_ucb)
+ {
+- struct ucb1x00 *ucb = devid;
++ struct task_struct *tsk = current;
++ DECLARE_WAITQUEUE(wait, tsk);
++ struct ucb1x00 *ucb = _ucb;
+ struct ucb1x00_irq *irq;
+ unsigned int isr, i;
+
+- ucb1x00_enable(ucb);
+- isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS);
+- ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
+- ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++ ucb->rtask = tsk;
+
+- for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++)
+- if (isr & 1 && irq->fn)
+- irq->fn(i, irq->devid);
+- ucb1x00_disable(ucb);
++ daemonize();
++ reparent_to_init();
++ tsk->tty = NULL;
++ tsk->policy = SCHED_FIFO;
++ tsk->rt_priority = 1;
++ strcpy(tsk->comm, "kUCB1x00d");
++
++ /* only want to receive SIGKILL */
++ spin_lock_irq(&tsk->sigmask_lock);
++ siginitsetinv(&tsk->blocked, sigmask(SIGKILL));
++ recalc_sigpending(tsk);
++ spin_unlock_irq(&tsk->sigmask_lock);
++
++ add_wait_queue(&ucb->irq_wait, &wait);
++ set_task_state(tsk, TASK_INTERRUPTIBLE);
++ complete(&ucb->complete);
++
++ for (;;) {
++ if (signal_pending(tsk))
++ break;
++ enable_irq(ucb->irq);
++ schedule();
++
++ ucb1x00_enable(ucb);
++ isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS);
++ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
++ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++
++ for (i = 0, irq = ucb->irq_handler;
++ i < 16 && isr;
++ i++, isr >>= 1, irq++)
++ if (isr & 1 && irq->fn)
++ irq->fn(i, irq->devid);
++ ucb1x00_disable(ucb);
++
++ set_task_state(tsk, TASK_INTERRUPTIBLE);
++ }
++
++ remove_wait_queue(&ucb->irq_wait, &wait);
++ ucb->rtask = NULL;
++ complete_and_exit(&ucb->complete, 0);
++}
++
++static void ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs)
++{
++ struct ucb1x00 *ucb = devid;
++ disable_irq(irqnr);
++ wake_up(&ucb->irq_wait);
+ }
+
+ /**
+@@ -291,6 +354,11 @@
+ spin_lock_irqsave(&ucb->lock, flags);
+
+ ucb1x00_enable(ucb);
++
++ /* This prevents spurious interrupts on the UCB1400 */
++ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 1 << idx);
++ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++
+ if (edges & UCB_RISING) {
+ ucb->irq_ris_enbl |= 1 << idx;
+ ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
+@@ -456,6 +524,7 @@
+ unsigned int irq_gpio_pin = 0;
+ int irq, default_irq = NO_IRQ;
+
++#ifdef CONFIG_ARCH_SA1100
+ if (machine_is_adsbitsy())
+ default_irq = IRQ_GPCIN4;
+
+@@ -514,12 +583,40 @@
+ }
+ #endif
+
++#endif /* CONFIG_ARCH_SA1100 */
++
++#ifdef CONFIG_ARCH_PXA_IDP
++ if (machine_is_pxa_idp()) {
++ default_irq = TOUCH_PANEL_IRQ;
++ irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ);
++ GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin);
++ }
++#endif
++
++#ifdef CONFIG_ARCH_TRIZEPS2
++ if (machine_is_trizeps2()) {
++ default_irq = TOUCH_PANEL_IRQ;
++ irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ);
++ GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin);
++ }
++#endif
++
++
++#ifdef CONFIG_PXA_CERF_PDA
++ if (machine_is_pxa_cerf()) {
++ irq_gpio_pin = CERF_GPIO_UCB1400_IRQ;
++ }
++#endif
++
+ /*
+ * Eventually, this will disappear.
+ */
+ if (irq_gpio_pin)
++#ifdef CONFIG_ARCH_PXA_IDP
++ set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_FALLING_EDGE);
++#else
+ set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_RISING_EDGE);
+-
++#endif
+ irq = ucb1x00_detect_irq(ucb);
+ if (irq != NO_IRQ) {
+ if (default_irq != NO_IRQ && irq != default_irq)
+@@ -541,21 +638,7 @@
+
+ struct ucb1x00 *my_ucb;
+
+-/**
+- * ucb1x00_get - get the UCB1x00 structure describing a chip
+- * @ucb: UCB1x00 structure describing chip
+- *
+- * Return the UCB1x00 structure describing a chip.
+- *
+- * FIXME: Currently very noddy indeed, which currently doesn't
+- * matter since we only support one chip.
+- */
+-struct ucb1x00 *ucb1x00_get(void)
+-{
+- return my_ucb;
+-}
+-
+-static int __init ucb1x00_init(void)
++static int ucb1x00_init_helper(void)
+ {
+ struct mcp *mcp;
+ unsigned int id;
+@@ -568,23 +651,28 @@
+ mcp_enable(mcp);
+ id = mcp_reg_read(mcp, UCB_ID);
+
+- if (id != UCB_ID_1200 && id != UCB_ID_1300) {
++ if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_1400) {
+ printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
+ goto out;
+ }
+
++ /* distinguish between UCB1400 revs 1B and 2A */
++ if (id == UCB_ID_1400 && mcp_reg_read(mcp, 0x00) == 0x002a)
++ id = UCB_ID_1400_BUGGY;
++
+ my_ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL);
+ ret = -ENOMEM;
+ if (!my_ucb)
+ goto out;
+
++#ifdef CONFIG_ARCH_SA1100
+ if (machine_is_shannon()) {
+ /* reset the codec */
+ GPDR |= SHANNON_GPIO_CODEC_RESET;
+ GPCR = SHANNON_GPIO_CODEC_RESET;
+ GPSR = SHANNON_GPIO_CODEC_RESET;
+-
+ }
++#endif
+
+ memset(my_ucb, 0, sizeof(struct ucb1x00));
+
+@@ -599,13 +687,12 @@
+ if (ret)
+ goto out;
+
++ init_waitqueue_head(&my_ucb->irq_wait);
+ ret = request_irq(my_ucb->irq, ucb1x00_irq, 0, "UCB1x00", my_ucb);
+ if (ret) {
+ printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
+ my_ucb->irq, ret);
+- kfree(my_ucb);
+- my_ucb = NULL;
+- goto out;
++ goto irq_err;
+ }
+
+ #ifdef CONFIG_PM
+@@ -616,16 +703,55 @@
+ my_ucb->pmdev->data = my_ucb;
+ #endif
+
++ init_completion(&my_ucb->complete);
++ ret = kernel_thread(ucb1x00_thread, my_ucb, CLONE_FS | CLONE_FILES);
++ if (ret >= 0) {
++ wait_for_completion(&my_ucb->complete);
++ ret = 0;
++ goto out;
++ }
++
++ free_irq(my_ucb->irq, my_ucb);
++irq_err:
++ kfree(my_ucb);
++ my_ucb = NULL;
+ out:
+ mcp_disable(mcp);
+ no_mcp:
+ return ret;
+ }
+
++/**
++ * ucb1x00_get - get the UCB1x00 structure describing a chip
++ * @ucb: UCB1x00 structure describing chip
++ *
++ * Return the UCB1x00 structure describing a chip.
++ *
++ * FIXME: Currently very noddy indeed, which currently doesn't
++ * matter since we only support one chip.
++ */
++struct ucb1x00 *ucb1x00_get(void)
++{
++ if( !my_ucb) ucb1x00_init_helper();
++
++ return my_ucb;
++}
++
++static int __init ucb1x00_init(void)
++{
++ /* check if driver is already initialized */
++ if( my_ucb) return 0;
++
++ return ucb1x00_init_helper();
++}
++
+ static void __exit ucb1x00_exit(void)
+ {
++ send_sig(SIGKILL, my_ucb->rtask, 1);
++ wait_for_completion(&my_ucb->complete);
+ free_irq(my_ucb->irq, my_ucb);
+ kfree(my_ucb);
++ my_ucb = 0;
+ }
+
+ module_init(ucb1x00_init);
+--- linux-2.4.27/drivers/misc/ucb1x00-ts.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/misc/ucb1x00-ts.c
+@@ -35,7 +35,11 @@
+ /*
+ * Define this if you want the UCB1x00 stuff to talk to the input layer
+ */
++#ifdef CONFIG_INPUT
++#define USE_INPUT
++#else
+ #undef USE_INPUT
++#endif
+
+ #ifndef USE_INPUT
+
+@@ -73,7 +77,7 @@
+ struct pm_dev *pmdev;
+ #endif
+
+- wait_queue_head_t irq_wait;
++ struct semaphore irq_wait;
+ struct semaphore sem;
+ struct completion init_exit;
+ struct task_struct *rtask;
+@@ -259,6 +263,11 @@
+ input_report_abs(&ts->idev, ABS_PRESSURE, pressure);
+ }
+
++static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
++{
++ input_report_abs(&ts->idev, ABS_PRESSURE, 0);
++}
++
+ static int ucb1x00_ts_open(struct input_dev *idev)
+ {
+ struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev;
+@@ -304,10 +313,15 @@
+ */
+ static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts)
+ {
+- ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+- UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
+- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+- UCB_TS_CR_MODE_INT);
++ if (ts->ucb->id == UCB_ID_1400_BUGGY)
++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
++ UCB_TS_CR_MODE_INT);
++ else
++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
++ UCB_TS_CR_MODE_INT);
+ }
+
+ /*
+@@ -397,13 +411,13 @@
+ /*
+ * This is a RT kernel thread that handles the ADC accesses
+ * (mainly so we can use semaphores in the UCB1200 core code
+- * to serialise accesses to the ADC).
++ * to serialise accesses to the ADC). The UCB1400 access
++ * functions are expected to be able to sleep as well.
+ */
+ static int ucb1x00_thread(void *_ts)
+ {
+ struct ucb1x00_ts *ts = _ts;
+ struct task_struct *tsk = current;
+- DECLARE_WAITQUEUE(wait, tsk);
+ int valid;
+
+ ts->rtask = tsk;
+@@ -429,10 +443,8 @@
+
+ valid = 0;
+
+- add_wait_queue(&ts->irq_wait, &wait);
+ for (;;) {
+ unsigned int x, y, p, val;
+- signed long timeout;
+
+ ts->restart = 0;
+
+@@ -457,8 +469,6 @@
+ val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
+
+ if (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)) {
+- set_task_state(tsk, TASK_INTERRUPTIBLE);
+-
+ ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
+ ucb1x00_disable(ts->ucb);
+
+@@ -471,7 +481,15 @@
+ valid = 0;
+ }
+
+- timeout = MAX_SCHEDULE_TIMEOUT;
++ /*
++ * Since ucb1x00_enable_irq() might sleep due
++ * to the way the UCB1400 regs are accessed, we
++ * can't use set_task_state() before that call,
++ * and not changing state before enabling the
++ * interrupt is racy. A semaphore solves all
++ * those issues quite nicely.
++ */
++ down_interruptible(&ts->irq_wait);
+ } else {
+ ucb1x00_disable(ts->ucb);
+
+@@ -486,16 +504,13 @@
+ }
+
+ set_task_state(tsk, TASK_INTERRUPTIBLE);
+- timeout = HZ / 100;
++ schedule_timeout(HZ / 100);
+ }
+
+- schedule_timeout(timeout);
+ if (signal_pending(tsk))
+ break;
+ }
+
+- remove_wait_queue(&ts->irq_wait, &wait);
+-
+ ts->rtask = NULL;
+ ucb1x00_ts_evt_clear(ts);
+ complete_and_exit(&ts->init_exit, 0);
+@@ -509,7 +524,7 @@
+ {
+ struct ucb1x00_ts *ts = id;
+ ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
+- wake_up(&ts->irq_wait);
++ up(&ts->irq_wait);
+ }
+
+ static int ucb1x00_ts_startup(struct ucb1x00_ts *ts)
+@@ -525,7 +540,7 @@
+ if (ts->rtask)
+ panic("ucb1x00: rtask running?");
+
+- init_waitqueue_head(&ts->irq_wait);
++ sema_init(&ts->irq_wait, 0);
+ ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
+ if (ret < 0)
+ goto out;
+@@ -585,7 +600,7 @@
+ * after sleep.
+ */
+ ts->restart = 1;
+- wake_up(&ts->irq_wait);
++ up(&ts->irq_wait);
+ }
+ return 0;
+ }
+--- linux-2.4.27/drivers/misc/ucb1x00.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/misc/ucb1x00.h
+@@ -10,8 +10,47 @@
+ #ifndef UCB1200_H
+ #define UCB1200_H
+
++#ifdef CONFIG_ARCH_PXA
++
++/* ucb1400 aclink register mappings: */
++
++#define UCB_IO_DATA 0x5a
++#define UCB_IO_DIR 0x5c
++#define UCB_IE_RIS 0x5e
++#define UCB_IE_FAL 0x60
++#define UCB_IE_STATUS 0x62
++#define UCB_IE_CLEAR 0x62
++#define UCB_TS_CR 0x64
++#define UCB_ADC_CR 0x66
++#define UCB_ADC_DATA 0x68
++#define UCB_ID 0x7e /* 7c is mfr id, 7e part id (from aclink spec) */
++
++#define UCB_ADC_DAT(x) ((x) & 0x3ff)
++
++#else
++
++/* ucb1x00 SIB register mappings: */
++
+ #define UCB_IO_DATA 0x00
+ #define UCB_IO_DIR 0x01
++#define UCB_IE_RIS 0x02
++#define UCB_IE_FAL 0x03
++#define UCB_IE_STATUS 0x04
++#define UCB_IE_CLEAR 0x04
++#define UCB_TC_A 0x05
++#define UCB_TC_B 0x06
++#define UCB_AC_A 0x07
++#define UCB_AC_B 0x08
++#define UCB_TS_CR 0x09
++#define UCB_ADC_CR 0x0a
++#define UCB_ADC_DATA 0x0b
++#define UCB_ID 0x0c
++#define UCB_MODE 0x0d
++
++#define UCB_ADC_DAT(x) (((x) & 0x7fe0) >> 5)
++
++#endif
++
+
+ #define UCB_IO_0 (1 << 0)
+ #define UCB_IO_1 (1 << 1)
+@@ -24,10 +63,6 @@
+ #define UCB_IO_8 (1 << 8)
+ #define UCB_IO_9 (1 << 9)
+
+-#define UCB_IE_RIS 0x02
+-#define UCB_IE_FAL 0x03
+-#define UCB_IE_STATUS 0x04
+-#define UCB_IE_CLEAR 0x04
+ #define UCB_IE_ADC (1 << 11)
+ #define UCB_IE_TSPX (1 << 12)
+ #define UCB_IE_TSMX (1 << 13)
+@@ -36,11 +71,9 @@
+
+ #define UCB_IRQ_TSPX 12
+
+-#define UCB_TC_A 0x05
+ #define UCB_TC_A_LOOP (1 << 7) /* UCB1200 */
+ #define UCB_TC_A_AMPL (1 << 7) /* UCB1300 */
+
+-#define UCB_TC_B 0x06
+ #define UCB_TC_B_VOICE_ENA (1 << 3)
+ #define UCB_TC_B_CLIP (1 << 4)
+ #define UCB_TC_B_ATT (1 << 6)
+@@ -49,14 +82,11 @@
+ #define UCB_TC_B_IN_ENA (1 << 14)
+ #define UCB_TC_B_OUT_ENA (1 << 15)
+
+-#define UCB_AC_A 0x07
+-#define UCB_AC_B 0x08
+ #define UCB_AC_B_LOOP (1 << 8)
+ #define UCB_AC_B_MUTE (1 << 13)
+ #define UCB_AC_B_IN_ENA (1 << 14)
+ #define UCB_AC_B_OUT_ENA (1 << 15)
+
+-#define UCB_TS_CR 0x09
+ #define UCB_TS_CR_TSMX_POW (1 << 0)
+ #define UCB_TS_CR_TSPX_POW (1 << 1)
+ #define UCB_TS_CR_TSMY_POW (1 << 2)
+@@ -72,7 +102,6 @@
+ #define UCB_TS_CR_TSPX_LOW (1 << 12)
+ #define UCB_TS_CR_TSMX_LOW (1 << 13)
+
+-#define UCB_ADC_CR 0x0a
+ #define UCB_ADC_SYNC_ENA (1 << 0)
+ #define UCB_ADC_VREFBYP_CON (1 << 1)
+ #define UCB_ADC_INP_TSPX (0 << 2)
+@@ -87,15 +116,13 @@
+ #define UCB_ADC_START (1 << 7)
+ #define UCB_ADC_ENA (1 << 15)
+
+-#define UCB_ADC_DATA 0x0b
+ #define UCB_ADC_DAT_VAL (1 << 15)
+-#define UCB_ADC_DAT(x) (((x) & 0x7fe0) >> 5)
+
+-#define UCB_ID 0x0c
+ #define UCB_ID_1200 0x1004
+ #define UCB_ID_1300 0x1005
++#define UCB_ID_1400 0x4304
++#define UCB_ID_1400_BUGGY 0x4303 /* fake ID */
+
+-#define UCB_MODE 0x0d
+ #define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
+ #define UCB_MODE_AUD_OFF_CAN (1 << 13)
+
+@@ -115,6 +142,9 @@
+ unsigned int irq;
+ struct semaphore adc_sem;
+ spinlock_t io_lock;
++ wait_queue_head_t irq_wait;
++ struct completion complete;
++ struct task_struct *rtask;
+ u16 id;
+ u16 io_dir;
+ u16 io_out;
+--- /dev/null
++++ linux-2.4.27/drivers/mmc/Config.in
+@@ -0,0 +1,12 @@
++mainmenu_option next_comment
++comment 'MMC device drivers'
++tristate 'Multi Media Card support' CONFIG_MMC
++if [ "$CONFIG_MMC" = "y" -o "$CONFIG_MMC" = "m" ]; then
++ dep_tristate 'PXA250 MMC driver' CONFIG_MMC_PXA $CONFIG_MMC
++ dep_tristate 'MMC block driver' CONFIG_MMC_BLOCK $CONFIG_MMC
++ if [ "$CONFIG_MMC_BLOCK" = "y" -o "$CONFIG_MMC_BLOCK" = "m" ]; then
++ bool ' MMC partitioning support' CONFIG_MMC_PARTITIONS
++ fi
++fi
++endmenu
++
+--- /dev/null
++++ linux-2.4.27/drivers/mmc/Makefile
+@@ -0,0 +1,14 @@
++#
++# Makefile for MMC drivers
++#
++
++export-objs := mmc_core.o
++
++obj-$(CONFIG_MMC) += mmc_core.o # mmc_test.o
++obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
++obj-$(CONFIG_MMC_PXA) += mmc_pxa.o
++# EXTRA_CFLAGS += -DCONFIG_MMC_DEBUG -DCONFIG_MMC_DEBUG_VERBOSE=2
++
++O_TARGET := mmcdrivers.o
++
++include $(TOPDIR)/Rules.make
+--- /dev/null
++++ linux-2.4.27/drivers/mmc/error.h
+@@ -0,0 +1,70 @@
++/*
++ * linux/include/linux/mmc/error.h
++ *
++ * Author: Vladimir Shebordaev
++ * Copyright: MontaVista Software Inc.
++ *
++ * $Id: error.h,v 0.2 2002/07/11 16:27:01 ted Exp ted $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef __MMC_ERROR_H__
++#define __MMC_ERROR_H__
++
++/* MMC protocol card error codes */
++#define MMC_CARD_STATUS_OUT_OF_RANGE (1<<31)
++#define MMC_CARD_STATUS_ADDRESS_ERROR (1<<30)
++#define MMC_CARD_STATUS_BLOCK_LEN_ERROR (1<<29)
++#define MMC_CARD_STATUS_ERASE_SEQ_ERROR (1<<28)
++#define MMC_CARD_STATUS_ERASE_PARAM (1<<27)
++#define MMC_CARD_STATUS_WP_VIOLATION (1<<26)
++#define MMC_CARD_STATUS_CARD_IS_LOCKED (1<<25)
++#define MMC_CARD_STATUS_LOCK_UNLOCK_FAILED (1<<24)
++#define MMC_CARD_STATUS_COM_CRC_ERROR (1<<23)
++#define MMC_CARD_STATUS_ILLEGAL_COMMAND (1<<22)
++#define MMC_CARD_STATUS_CARD_ECC_FAILED (1<<21)
++#define MMC_CARD_STATUS_CC_ERROR (1<<20)
++#define MMC_CARD_STATUS_ERROR (1<<19)
++#define MMC_CARD_STATUS_UNDERRUN (1<<18)
++#define MMC_CARD_STATUS_OVERRUN (1<<17)
++#define MMC_CARD_STATUS_CID_CSD_OVERWRITE (1<<16)
++#define MMC_CARD_STATUS_ERASE_RESET (1<<13)
++
++#define MMC_ERROR( fmt, args... ) printk( KERN_ERR "%s(): " fmt, __FUNCTION__, ##args )
++
++/*
++ * Error codes returned by MMC subsystem functions and
++ * error reporting function prototypes
++ */
++enum _mmc_error {
++/* controller errors */
++ MMC_ERROR_GENERIC = -10000,
++ MMC_ERROR_CRC_WRITE_ERROR = -10001,
++ MMC_ERROR_CRC_READ_ERROR = -10002,
++ MMC_ERROR_RES_CRC_ERROR = -10003,
++ MMC_ERROR_READ_TIME_OUT = -10004,
++ MMC_ERROR_TIME_OUT_RESPONSE = -10005,
++ MMC_ERROR_INVAL = -10006,
++/* protocol errors reported in card status (R1 response) */
++ MMC_ERROR_OUT_OF_RANGE = -10007,
++ MMC_ERROR_ADDRESS_ERROR = -10008,
++ MMC_ERROR_BLOCK_LEN_ERROR = -10009,
++ MMC_ERROR_ERASE_SEQ_ERROR = -10010,
++ MMC_ERROR_ERASE_PARAM = -10011,
++ MMC_ERROR_WP_VIOLATION = -10012,
++ MMC_ERROR_CARD_IS_LOCKED = -10013,
++ MMC_ERROR_LOCK_UNLOCK_FAILED = -10014,
++ MMC_ERROR_COM_CRC_ERROR = -10015,
++ MMC_ERROR_ILLEGAL_COMMAND = -10016,
++ MMC_ERROR_CARD_ECC_FAILED = -10017,
++ MMC_ERROR_CC_ERROR = -10018,
++ MMC_ERROR_ERROR = -10019,
++ MMC_ERROR_UNDERRUN = -10020,
++ MMC_ERROR_OVERRUN = -10021,
++ MMC_ERROR_CID_CSD_OVERWRITE = -10022,
++ /* FIXME: incomplete */
++ MMC_ERROR_ERASE_RESET = -10025
++};
++#endif /* __MMC_ERROR_H__ */
+--- /dev/null
++++ linux-2.4.27/drivers/mmc/mmc.h
+@@ -0,0 +1,463 @@
++/*
++ * linux/drivers/mmc/mmc.h
++ *
++ * Author: Vladimir Shebordaev
++ * Copyright: MontaVista Software Inc.
++ *
++ * $Id: mmc.h,v 0.3.1.8 2002/09/18 12:58:00 ted Exp ted $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef __MMC_P_H__
++#define __MMC_P_H__
++
++#ifdef __KERNEL__
++
++#include <linux/types.h>
++#include <linux/slab.h>
++
++#include <linux/spinlock.h>
++
++#ifdef CONFIG_PROC_FS
++#include <linux/proc_fs.h>
++#endif
++
++#include <asm/semaphore.h>
++#include <mmc/types.h>
++#include <mmc/mmc.h>
++
++#include "types.h"
++
++#include "error.h"
++
++#define MMC_CONTROLLERS_MAX (4)
++#define MMC_CARDS_MAX (16)
++
++/* test device */
++#define MMC_TEST_MAJOR (240)
++#define MMC_TEST_TRANSFER_MODE_DEFAULT MMC_TRANSFER_MODE_BLOCK_SINGLE
++
++/* block device */
++#define MMC_BLOCK_MAJOR (241) /* FIXME: MMC_MAJOR */
++#define MMC_BLOCK_DEVICES_MAX (1<<MINORBITS) /* FIXME */
++#define MMC_BLOCK_SECT_SIZE (512) /* FIXME */
++#define MMC_BLOCK_PARTNBITS (3)
++
++/* Device minor number encoding:
++ * [7:6] - host
++ * [5:3] - card slot number
++ * [2:0] - partition number
++ */
++#define MMC_MINOR_HOST_SHIFT (6)
++#define MMC_MINOR_CARD_MASK (0x07)
++
++/*
++ * MMC controller abstraction
++ */
++enum _mmc_controller_state {
++ MMC_CONTROLLER_ABSENT = 0,
++ MMC_CONTROLLER_FOUND,
++ MMC_CONTROLLER_INITIALIZED,
++ MMC_CONTROLLER_UNPLUGGED
++};
++
++enum _mmc_dir {
++ MMC_READ = 1,
++ MMC_WRITE
++};
++
++enum _mmc_buftype {
++ MMC_USER = 1,
++ MMC_KERNEL
++};
++
++struct _mmc_data_transfer_req_rec {
++ mmc_dir_t cmd; /* read or write operation requested */
++ mmc_transfer_mode_t mode; /* requested data transfer mode */
++ mmc_buftype_t type; /* whether supplied buffer resides in user or kernel space */
++ char *buf; /* poiner to the caller's buffer */
++ ssize_t cnt; /* number of bytes to transfer */
++ loff_t addr; /* card address */
++ ssize_t blksz; /* block size as for CSD[READ_BL_LEN] or CSD[WRITE_BL_LEN] */
++ ssize_t nob; /* number of blocks to transfer */
++};
++
++struct _mmc_controller_tmpl_rec {
++ struct module *owner; /* driver module */
++ char name[16];
++
++ const ssize_t block_size_max; /* max acceptable block size */
++ const ssize_t nob_max; /* max blocks per one data transfer */
++
++ int (*probe)( mmc_controller_t ); /* hardware probe */
++ int (*init)( mmc_controller_t ); /* initialize, e.g. request irq, DMA and allocate buffers */
++ void (*remove)( mmc_controller_t ); /* free resources */
++#if 0 /* CONFIG_HOTPLUG */
++ void (*attach)( void ); /|* controller hotplug callbacks *|/
++ void (*detach)( void );
++#endif
++#ifdef CONFIG_PM
++ int (*suspend)( mmc_controller_t ); /* power management callbacks */
++ void (*resume)( mmc_controller_t );
++#endif
++
++/* MMC protocol macros, v3.4, p.120 */
++ int (*init_card_stack)( mmc_controller_t );
++ int (*update_acq)( mmc_controller_t ); /* update card stack management data */
++ int (*single_card_acq)( mmc_controller_t );
++ int (*check_card_stack)( mmc_controller_t );
++ int (*setup_card)( mmc_controller_t, mmc_card_t );
++ int (*stream_read)( mmc_controller_t, mmc_data_transfer_req_t );
++ int (*read_block)( mmc_controller_t, mmc_data_transfer_req_t );
++ int (*read_mblock)( mmc_controller_t, mmc_data_transfer_req_t );
++ int (*stream_write)( mmc_controller_t, mmc_data_transfer_req_t );
++ int (*write_block)( mmc_controller_t, mmc_data_transfer_req_t );
++ int (*write_mblock)( mmc_controller_t, mmc_data_transfer_req_t );
++/* TODO:
++ int (*sg_io)( mmc_controller_t, sg_list_t );
++*/
++/* TODO:
++ * 1) erase group macros
++ * int (*erase_group)( mmc_controller_t, mmc_erase_group_info_t );
++ * 2) write protection macros;
++ * int (*set_write_prot)( mmc_controller_t, mmc_write_protection_info_t )
++ * 3) lock/password management macros;
++ */
++};
++
++#ifndef MMC_CTRLR_BLKSZ_DEFAULT
++#define MMC_CTRLR_BLKSZ_DEFAULT (512)
++#endif
++
++#ifndef MMC_CTRLR_NOB_DEFAULT
++#define MMC_CTRLR_NOB_DEFAULT (1)
++#endif
++
++struct _mmc_card_rec {
++/* public card interface */
++ struct _mmc_card_info_rec info; /* see <linux/mmc/mmc.h> */
++
++/* private kernel specific data */
++ mmc_state_t state; /* card's state as per last operation */
++ mmc_card_t next; /* link to the stack */
++ mmc_controller_t ctrlr; /* back reference to the controller */
++ int usage; /* reference count */
++ int slot; /* card's number for device reference */
++/* TODO: async I/O queue */
++#ifdef CONFIG_PROC_FS
++ proc_dir_entry_t proc;
++ char proc_name[16];
++#endif
++ unsigned long card_data[0] /* card specific data */
++ __attribute__((aligned (sizeof(unsigned long))));
++};
++
++struct _mmc_card_stack_rec {
++ mmc_card_t first; /* first card on the stack */
++ mmc_card_t last; /* last card on the stack */
++ mmc_card_t selected; /* currently selected card */
++ int ncards;
++};
++
++struct _mmc_controller_rec {
++ mmc_controller_state_t state; /* found, initialized, unplugged... */
++ int usage; /* reference count */
++ int slot; /* host's number for device reference */
++ semaphore_t io_sem; /* I/O serialization */
++ rwsemaphore_t update_sem; /* card stack check/update serialization */
++
++ mmc_controller_tmpl_t tmpl; /* methods provided by the driver */
++ mmc_card_stack_rec_t stack; /* card stack management data */
++
++ u32 rca_next; /* next RCA to assign */
++ int slot_next; /* next slot number to assign */
++#ifdef CONFIG_PROC_FS
++ char proc_name[16];
++ proc_dir_entry_t proc;
++#endif
++ unsigned long host_data[0] /* driver can request some extra space */
++ __attribute__((aligned (sizeof(unsigned long))));
++};
++
++/*
++ * MMC core interface
++ */
++enum _mmc_reg_type {
++ MMC_REG_TYPE_USER = 1,
++ MMC_REG_TYPE_HOST,
++ MMC_REG_TYPE_CARD
++};
++
++struct _mmc_notifier_rec {
++ struct _mmc_notifier_rec *next;
++ mmc_notifier_fn_t add;
++ mmc_notifier_fn_t remove;
++};
++
++enum _mmc_response {
++ MMC_NORESPONSE = 1,
++ MMC_R1,
++ MMC_R2,
++ MMC_R3,
++ MMC_R4,
++ MMC_R5
++};
++
++#undef EXTERN
++#ifndef __MMC_CORE_IMPLEMENTATION__
++#define EXTERN extern
++#else
++#define EXTERN /* empty */
++#endif
++
++EXTERN void *mmc_register( mmc_reg_type_t, void *, size_t );
++EXTERN void mmc_unregister( mmc_reg_type_t, void * );
++EXTERN int mmc_update_card_stack( int );
++
++EXTERN mmc_card_t mmc_get_card( int, int );/* get reference to the card */
++EXTERN void mmc_put_card( mmc_card_t ); /* release card reference */
++
++EXTERN int mmc_notify_add( mmc_card_t ); /* user notification */
++EXTERN int mmc_notify_remove( mmc_card_t );
++
++EXTERN ssize_t mmc_read( mmc_card_t, mmc_transfer_mode_t, char *, size_t, loff_t * ); /* generic read */
++EXTERN ssize_t mmc_write( mmc_card_t, mmc_transfer_mode_t, const char *, size_t, loff_t * ); /* generic write */
++EXTERN int mmc_ioctl( mmc_card_t, unsigned int, unsigned long ); /* generic ioctl */
++/*
++ * TODO: [?m.b. ioctl()] to erase, lock and write protect
++ * 1) mmc_erase
++ * 2) mmc_write_prot
++ * 3) mmc_lock
++ */
++#undef EXTERN
++
++static inline mmc_card_t __mmc_card_alloc( size_t extra )
++{
++ mmc_card_t ret = kmalloc( sizeof( mmc_card_rec_t ) + extra, GFP_KERNEL );
++
++ if ( ret ) {
++ memset( ret, 0, sizeof( mmc_card_rec_t ) + extra );
++ }
++
++ return ret;
++}
++
++static inline void __mmc_card_free( mmc_card_t card )
++{
++ if ( card ) {
++ kfree( card );
++ }
++}
++
++static inline mmc_card_stack_t __mmc_card_stack_init( mmc_card_stack_t stack )
++{
++ mmc_card_stack_t ret = NULL;
++ if ( stack ) {
++ memset( stack, 0, sizeof( mmc_card_stack_rec_t ) );
++ ret = stack;
++ }
++ return ret;
++}
++
++static inline mmc_card_stack_t __mmc_card_stack_add( mmc_card_stack_t stack, mmc_card_t card )
++{
++ mmc_card_stack_t ret = NULL;
++
++ if ( stack && card ) {
++ card->next = NULL;
++
++ if ( stack->first ) {
++ stack->last->next = card;
++ stack->last = card;
++ } else
++ stack->first = stack->last = card;
++
++ ++stack->ncards;
++ ret = stack;
++ }
++ return ret;
++}
++
++static inline mmc_card_stack_t __mmc_card_stack_remove( mmc_card_stack_t stack, mmc_card_t card )
++{
++ mmc_card_stack_t ret = NULL;
++ register mmc_card_t prev;
++ int found = FALSE;
++
++ if ( !stack || !card )
++ goto error;
++
++ if ( stack->ncards > 0 ) {
++ if ( stack->first == card ) {
++ stack->first = stack->first->next;
++ if ( stack->last == card )
++ stack->last = stack->last->next;
++ found = TRUE;
++ } else {
++ for ( prev = stack->first; prev; prev = prev->next )
++ if ( prev->next == card ) {
++ found = TRUE;
++ break;
++ }
++ if ( found ) {
++ if ( prev->next == stack->last )
++ stack->last = prev->next;
++ prev->next = prev->next->next;
++ }
++ }
++ if ( found ) {
++ --stack->ncards;
++ ret = stack;
++ }
++ }
++error:
++ return ret;
++}
++
++static inline void __mmc_card_stack_free( mmc_card_stack_t stack )
++{
++ mmc_card_t card, next;
++
++ if ( stack && (stack->ncards > 0) ) {
++ card = stack->first;
++ while ( card ) {
++ next = card->next;
++ kfree( card );
++ card = next;
++ }
++ __mmc_card_stack_init( stack );
++ }
++}
++
++static inline int __mmc_card_stack_foreach( mmc_card_stack_t stack, mmc_notifier_fn_t fn, int unplugged_also )
++{
++ int ret = 0;
++ register mmc_card_t card = NULL;
++
++ if ( stack && fn ) {
++ for ( card = stack->first; card; card = card->next )
++ if ( (card->state != MMC_CARD_STATE_UNPLUGGED)
++ || unplugged_also )
++ if ( fn( card ) ) {
++ ret = -card->slot;
++ break;
++ }
++ }
++
++ return ret;
++}
++
++/*
++ * Debugging macros
++ */
++#ifdef CONFIG_MMC_DEBUG
++
++#define MMC_DEBUG_LEVEL0 (0) /* major */
++#define MMC_DEBUG_LEVEL1 (1)
++#define MMC_DEBUG_LEVEL2 (2) /* device */
++#define MMC_DEBUG_LEVEL3 (3) /* protocol */
++#define MMC_DEBUG_LEVEL4 (4) /* everything */
++
++#define MMC_DEBUG(n, args...) \
++if (n <= CONFIG_MMC_DEBUG_VERBOSE) { \
++ printk(KERN_INFO __FUNCTION__ "(): " args); \
++}
++#define __ENTER0( ) MMC_DEBUG( MMC_DEBUG_LEVEL2, "entry\n" );
++#define __LEAVE0( ) MMC_DEBUG( MMC_DEBUG_LEVEL2, "exit\n" );
++#define __ENTER( format, args... ) MMC_DEBUG( MMC_DEBUG_LEVEL2, "entry: " format "\n", args );
++#define __LEAVE( format, args... ) MMC_DEBUG( MMC_DEBUG_LEVEL2, "exit: " format "\n", args );
++
++#define MMC_DUMP_CSD( card ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \
++"CSD register:\n" \
++" csd_structure=%u\n" \
++" spec_vers=%u\n" \
++" taac=%x\n" \
++" nsac=%x\n" \
++" tran_speed=%x\n" \
++" ccc=%x\n" \
++" read_bl_len=%u\n" \
++" read_bl_partial=%u\n" \
++" write_blk_misalign=%u\n" \
++" read_blk_misalign=%u\n" \
++" dsr_imp=%u\n" \
++" c_size=%u\n" \
++" vdd_r_curr_min=%u\n" \
++" vdd_r_curr_max=%u\n" \
++" vdd_w_curr_min=%u\n" \
++" vdd_w_curr_max=%u\n" \
++" c_size_mult=%u\n" \
++" erase_grp_size=%u\n" \
++" erase_grp_mult=%u\n" \
++" wp_grp_size=%u\n" \
++" wp_grp_enable=%u\n" \
++" default_ecc=%u\n" \
++" r2w_factor=%u\n" \
++" write_bl_len=%u\n" \
++" write_bl_partial=%u\n" \
++" content_prot_app=%u\n" \
++" file_format_grp=%u\n" \
++" copy=%u\n" \
++" perm_write_protect=%d\n" \
++" tmp_write_protect=%d\n" \
++" file_format=%d\n" \
++" ecc=%d\n", \
++card->info.csd.csd_structure, \
++card->info.csd.spec_vers, \
++card->info.csd.taac, \
++card->info.csd.nsac, \
++card->info.csd.tran_speed, \
++card->info.csd.ccc, \
++card->info.csd.read_bl_len, \
++card->info.csd.read_bl_partial, \
++card->info.csd.write_blk_misalign, \
++card->info.csd.read_blk_misalign, \
++card->info.csd.dsr_imp, \
++card->info.csd.c_size, \
++card->info.csd.vdd_r_curr_min, \
++card->info.csd.vdd_r_curr_max, \
++card->info.csd.vdd_w_curr_min, \
++card->info.csd.vdd_w_curr_max, \
++card->info.csd.c_size_mult, \
++card->info.csd.erase_grp_size, \
++card->info.csd.erase_grp_mult, \
++card->info.csd.wp_grp_size, \
++card->info.csd.wp_grp_enable, \
++card->info.csd.default_ecc, \
++card->info.csd.r2w_factor, \
++card->info.csd.write_bl_len, \
++card->info.csd.write_bl_partial, \
++card->info.csd.content_prot_app, \
++card->info.csd.file_format_grp, \
++card->info.csd.copy, \
++card->info.csd.perm_write_protect, \
++card->info.csd.tmp_write_protect, \
++card->info.csd.file_format, \
++card->info.csd.ecc );
++
++#else /* CONFIG_MMC_DEBUG */
++#define MMC_DEBUG(n, args...) /* empty */
++#define __ENTER0( ) /* empty */
++#define __LEAVE0( ) /* empty */
++#define __ENTER( args... ) /* empty */
++#define __LEAVE( args... ) /* empty */
++#define MMC_DUMP_CSD( card ) /* empty */
++#endif /* CONFIG_MMC_DEBUG */
++
++/*
++ * Miscellaneous defines
++ */
++#ifndef MMC_DUMP_R1
++#define MMC_DUMP_R1( ctrlr ) /* empty */
++#endif
++#ifndef MMC_DUMP_R2
++#define MMC_DUMP_R2( ctrlr ) /* empty */
++#endif
++#ifndef MMC_DUMP_R3
++#define MMC_DUMP_R3( ctrlr ) /* empty */
++#endif
++
++#endif /* __KERNEL__ */
++
++#endif /* __MMC_P_H__ */
+--- /dev/null
++++ linux-2.4.27/drivers/mmc/mmc_block.c
+@@ -0,0 +1,989 @@
++/*
++ * linux/drivers/mmc/mmc_block.c
++ * driver for the block device on the MMC card
++ *
++ * Author: Vladimir Shebordaev
++ * Copyright: MontaVista Software Inc.
++ *
++ * $Id: mmc_block.c,v 0.3.1.16 2002/09/27 17:36:09 ted Exp ted $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/devfs_fs_kernel.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/hdreg.h>
++#include <linux/blkpg.h>
++#include <asm/uaccess.h>
++
++#include <mmc/types.h>
++#include <mmc/mmc.h>
++
++#include "types.h"
++#include "mmc.h"
++#include "error.h"
++
++#define MAJOR_NR MMC_BLOCK_MAJOR
++#define MAJOR_NAME "mmc"
++#define DEVICE_NAME "mmc_block"
++#define DEVICE_REQUEST mmc_block_request
++#define DEVICE_NR(device) (device)
++#define DEVICE_ON(device)
++#define DEVICE_OFF(device)
++#define DEVICE_NO_RANDOM
++#include <linux/blk.h>
++/* for old kernels... */
++#ifndef QUEUE_EMPTY
++#define QUEUE_EMPTY (!CURRENT)
++#endif
++#if LINUX_VERSION_CODE < 0x20300
++#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync)
++#else
++#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged)
++#endif
++
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
++#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
++#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
++#else
++#define BLK_INC_USE_COUNT do {} while(0)
++#define BLK_DEC_USE_COUNT do {} while(0)
++#endif
++
++#define MMC_BLOCK_RAW_DEVICE( device ) ((device>>MMC_BLOCK_PARTNBITS)<<MMC_BLOCK_PARTNBITS)
++#define MMC_BLOCK_MKDEV( host, slot ) \
++ MKDEV( MMC_BLOCK_MAJOR, \
++ (host<<MMC_MINOR_HOST_SHIFT) \
++ | (slot<<MMC_BLOCK_PARTNBITS) )
++
++typedef struct _mmc_block_device mmc_block_device_rec_t;
++typedef struct _mmc_block_device *mmc_block_device_t;
++
++struct _mmc_block_device {
++ mmc_card_t card;
++ int host;
++ int slot;
++ kdev_t rdev;
++ int usage;
++ semaphore_t sem;
++};
++
++static int mmc_block_blk_sizes[1<<MINORBITS];
++static int mmc_block_blk_blksizes[1<<MINORBITS];
++static int mmc_block_hardsect_sizes[1<<MINORBITS];
++static struct hd_struct mmc_block_partitions[1<<MINORBITS];
++
++/* Accessed under device table lock */
++static gendisk_rec_t mmc_block_gendisk = {
++ major: MMC_BLOCK_MAJOR,
++ major_name: MAJOR_NAME,
++ minor_shift: MMC_BLOCK_PARTNBITS,
++ max_p: (1<<MMC_BLOCK_PARTNBITS),
++ sizes: mmc_block_blk_sizes,
++ part: mmc_block_partitions
++};
++
++static mmc_block_device_rec_t mmc_block_device[1<<MINORBITS];
++static rwsemaphore_t mmc_block_device_sem;
++
++static inline void __mmc_block_rdlock_devices( void )
++{
++ down_read( &mmc_block_device_sem );
++}
++
++static inline void __mmc_block_rdunlock_devices( void )
++{
++ up_read( &mmc_block_device_sem );
++}
++
++static inline void __mmc_block_wrlock_devices( void )
++{
++ down_write( &mmc_block_device_sem );
++}
++
++static inline void __mmc_block_wrunlock_devices( void )
++{
++ up_write( &mmc_block_device_sem );
++}
++
++static inline void __mmc_block_lock_device( kdev_t rdev )
++{
++ __mmc_block_rdlock_devices();
++ down( &mmc_block_device[MINOR( rdev )].sem );
++}
++
++static inline void __mmc_block_unlock_device( kdev_t rdev )
++{
++ up( &mmc_block_device[MINOR( rdev )].sem );
++ __mmc_block_rdunlock_devices();
++}
++
++static inline void __mmc_block_device_init( int minor )
++{
++ mmc_block_device_t dev = &mmc_block_device[minor];
++
++ dev->usage = 0;
++ dev->card = NULL;
++ dev->host = minor >> MMC_MINOR_HOST_SHIFT;
++ dev->slot = (minor & MMC_MINOR_CARD_MASK)>>MMC_BLOCK_PARTNBITS;
++ dev->rdev = MKDEV( MMC_BLOCK_MAJOR, minor );
++}
++
++static inline int __mmc_block_validate_device( kdev_t rdev )
++{
++ int ret = -1;
++ int minor = MINOR( rdev );
++
++ if ( mmc_block_device[minor].card
++ && (mmc_block_gendisk.part[minor].nr_sects > 0) )
++ ret = 0;
++
++ return ret;
++}
++
++static inline int __mmc_block_invalidate_card( mmc_card_t card, int invalidate )
++{
++ int ret = 0;
++ kdev_t start;
++ int minor;
++
++ __ENTER( "card = 0x%p", card );
++
++ if ( card && card->ctrlr ) {
++ register int i;
++
++ start = MMC_BLOCK_MKDEV( card->ctrlr->slot, card->slot );
++ minor = MINOR( start );
++
++ __mmc_block_wrlock_devices();
++ for ( i = mmc_block_gendisk.max_p - 1; i >= 0; --i ) {
++ if ( invalidate )
++ invalidate_device( start + i, 0 );
++
++ __mmc_block_device_init( minor + i );
++
++ mmc_block_gendisk.part[minor + i].nr_sects = 0;
++ mmc_block_gendisk.part[minor + i].start_sect = 0;
++ }
++ __mmc_block_wrunlock_devices();
++ }
++
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++static inline int mmc_block_invalidate_card( int host, int slot, int invalidate )
++{
++ int ret = 0;
++ kdev_t start;
++ int minor;
++
++ __ENTER( "host=%d slot=%d", host, slot );
++
++ if ( (host >= 0) && (slot >= 0) ) {
++ register int i;
++ mmc_card_t card = NULL;
++
++ start = MMC_BLOCK_MKDEV( host, slot );
++ minor = MINOR( start );
++
++ __mmc_block_wrlock_devices();
++ for ( i = mmc_block_gendisk.max_p - 1; i >= 0; --i ) {
++ if ( !card )
++ card = mmc_block_device[minor + i].card;
++
++ if ( invalidate )
++ invalidate_device( start + i, 0 );
++
++ __mmc_block_device_init( minor + i );
++
++ mmc_block_gendisk.part[minor + i].nr_sects = 0;
++ mmc_block_gendisk.part[minor + i].start_sect = 0;
++ }
++ if ( card )
++ mmc_put_card( card );
++ __mmc_block_wrunlock_devices();
++ }
++
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++/* Get device reference locked for writing */
++static inline mmc_block_device_t __mmc_block_get_device( kdev_t rdev )
++{
++ mmc_block_device_t ret = NULL;
++ u8 minor = MINOR( rdev );
++ int host_no, card_no;
++
++ __ENTER( "rdev=%x:%x", MAJOR( rdev ), MINOR( rdev ) );
++
++ host_no = minor >> MMC_MINOR_HOST_SHIFT;
++ if ( host_no >= MMC_CONTROLLERS_MAX )
++ goto error;
++
++ card_no = (minor & MMC_MINOR_CARD_MASK)>>MMC_BLOCK_PARTNBITS;
++ if ( card_no >= MMC_CARDS_MAX )
++ goto error;
++
++ __mmc_block_lock_device( rdev );
++ if ( __mmc_block_validate_device( rdev ) ) {
++ __mmc_block_unlock_device( rdev );
++ goto error;
++ }
++
++ ret = &mmc_block_device[minor];
++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "(%x:%x) card=%p, dusage=%d\n",
++ MAJOR( ret->rdev ), MINOR( ret->rdev ),
++ ret->card, ret->usage );
++error:
++ __LEAVE( "ret=0x%p", ret );
++ return ret;
++}
++
++/* Unlocks the device */
++static inline void __mmc_block_put_device( mmc_block_device_t dev )
++{
++ __ENTER0();
++
++ if ( dev ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "(%x:%x) card=%p, dusage=%d\n",
++ MAJOR( dev->rdev ), MINOR( dev->rdev ),
++ dev->card, dev->usage );
++ __mmc_block_unlock_device( dev->rdev );
++ }
++
++ __LEAVE0();
++}
++
++/* Atomically increases use count of the valid device */
++static inline mmc_block_device_t mmc_block_get_device( kdev_t rdev )
++{
++ mmc_block_device_t ret = NULL;
++
++ __ENTER0();
++
++ ret = __mmc_block_get_device( rdev );
++ if ( !ret )
++ goto error;
++
++ ret->usage++;
++ __mmc_block_put_device( ret );
++error:
++ __LEAVE( "ret=0x%p dusage=%d card=0x%p cusage=%d",
++ ret, ret ? ret->usage : -1,
++ ret ? ret->card : NULL,
++ ret ? (ret->card ? ret->card->usage : -1) : -1 );
++ return ret;
++}
++
++/* Check is there references to the card */
++static inline int __mmc_block_check_card( kdev_t rdev )
++{
++ int ret = TRUE;
++ int start = MINOR( MMC_BLOCK_RAW_DEVICE( rdev ) );
++ register int i;
++
++ for ( i = 0; i < mmc_block_gendisk.max_p; i++ )
++ if ( mmc_block_device[start + i].usage > 0 ) {
++ ret = FALSE;
++ break;
++ }
++
++ return ret;
++}
++
++/* Atomically decreases device use count */
++static inline void mmc_block_put_device( mmc_block_device_t dev )
++{
++ __ENTER0();
++
++ if ( dev ) {
++ int invalidate = FALSE;
++
++ __mmc_block_get_device( dev->rdev );
++ if ( dev->usage > 0 )
++ --dev->usage;
++
++ if ( dev->usage ) {
++ __mmc_block_put_device( dev );
++ goto out;
++
++ } else {
++ int host, slot;
++ mmc_card_t card = NULL;
++
++ invalidate = __mmc_block_check_card( dev->rdev );
++ if ( invalidate ) {
++ host = dev->card->ctrlr->slot;
++ slot = dev->card->slot;
++
++ if ( dev->card ) {
++ card = dev->card;
++ mmc_put_card( dev->card );
++ dev->card = NULL;
++ }
++ }
++ __mmc_block_put_device( dev );
++
++ if ( invalidate )
++ __mmc_block_invalidate_card( card, TRUE );
++ }
++
++ }
++out:
++ __LEAVE0();
++}
++
++static int mmc_block_open( struct inode *inode, struct file *file )
++{
++ int ret = -ENODEV;
++ mmc_block_device_t dev = NULL;
++
++ __ENTER0();
++
++ if ( !inode || !file )
++ goto error;
++
++ BLK_INC_USE_COUNT;
++
++ check_disk_change( inode->i_rdev );
++
++ dev = mmc_block_get_device( inode->i_rdev );
++ if ( !dev )
++ goto error;
++
++ dev = __mmc_block_get_device( inode->i_rdev );
++ if ( !dev )
++ goto error;
++
++ if ( file->f_mode & FMODE_WRITE ) { /* FIXME */
++ if ( dev->usage > 1 ) {
++ ret = -EBUSY;
++ __mmc_block_put_device( dev );
++ mmc_block_put_device( dev );
++ goto error;
++ }
++ }
++
++ __mmc_block_put_device( dev );
++
++ if ( file )
++ file->private_data = dev;
++
++ ret = 0;
++ goto out;
++error:
++ BLK_DEC_USE_COUNT;
++out:
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++static int mmc_block_release( struct inode *inode, struct file *file )
++{
++ int ret = -EINVAL;
++ mmc_block_device_t dev = NULL;
++
++ __ENTER( "inode=0x%p file=0x%p rdev=(%x:%x)", inode, file,
++ inode ? MAJOR( inode->i_rdev ) : 0xff,
++ inode ? MINOR( inode->i_rdev ) : 0xff );
++
++ if ( !file && !inode )
++ goto error;
++
++ if ( file )
++ dev = file->private_data;
++ else
++ dev = __mmc_block_get_device( inode->i_rdev );
++
++ if ( !dev ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid device\n" );
++ goto error;
++ }
++
++ if ( file ) {
++ mmc_block_put_device( dev );
++ file->private_data = NULL;
++
++ } else {
++ int invalidate = FALSE;
++
++ if ( dev->usage > 0 )
++ --dev->usage;
++
++ if ( dev->usage ) {
++ __mmc_block_put_device( dev );
++ goto out;
++
++ } else {
++ int host, slot;
++ mmc_card_t card = NULL;
++
++ invalidate = __mmc_block_check_card( dev->rdev );
++ if ( invalidate ) {
++ host = dev->card->ctrlr->slot;
++ slot = dev->card->slot;
++
++ if ( dev->card ) {
++ card = dev->card;
++ mmc_put_card( dev->card );
++ dev->card = NULL;
++ }
++ }
++ __mmc_block_put_device( dev );
++
++ if ( invalidate )
++ __mmc_block_invalidate_card( card, TRUE );
++
++ }
++ }
++
++out:
++ BLK_DEC_USE_COUNT;
++ ret = 0;
++error:
++ __LEAVE0();
++ return ret;
++}
++
++static int mmc_block_check_disk_change( kdev_t rdev )
++{
++ int ret = 0;
++#if 0
++ mmc_block_device_t dev = &mmc_block_device[MINOR( rdev )];
++
++ __mmc_block_lock_device( rdev );
++ if ( !dev->card )
++ ret = 1;
++ __mmc_block_unlock_device( rdev );
++#else
++ ret = 1;
++#endif
++ return ret;
++}
++
++static int mmc_block_revalidate( kdev_t rdev )
++{
++ int ret = 1;
++ mmc_card_t card;
++ mmc_block_device_t dev;
++ kdev_t start = MMC_BLOCK_RAW_DEVICE( rdev );
++ int minor = MINOR( start );
++ int host, slot;
++ int i;
++
++ __ENTER0();
++
++ (void)mmc_update_card_stack( MINOR( start )>>MMC_MINOR_HOST_SHIFT );
++
++ __mmc_block_wrlock_devices();
++
++ dev = &mmc_block_device[minor];
++ host = dev->host;
++ slot = dev->slot;
++
++ if ( dev->card ) { /* card has not been changed actually */
++ __mmc_block_wrunlock_devices();
++ goto out;
++
++ } else {
++ card = mmc_get_card( host, slot );
++ if ( !card ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "failed to get card: "
++ "host=%d, slot=%d\n", host, slot );
++ __mmc_block_wrunlock_devices();
++ goto error;
++ }
++ dev->card = card;
++ }
++ __mmc_block_wrunlock_devices();
++ /* FIXME */
++ __mmc_block_rdlock_devices(); /* handle the request for sector 0 */
++ grok_partitions( &mmc_block_gendisk, MINOR( start ),
++ mmc_block_gendisk.max_p,
++ card->info.capacity>>9 /* sectors */
++ );
++ __mmc_block_rdunlock_devices();
++ /* FIXME */
++ __mmc_block_wrlock_devices();
++ for ( i = start + mmc_block_gendisk.max_p - 1; i >= 0; --i ) {
++ int minor = MINOR( i );
++
++ dev = &mmc_block_device[minor];
++ if ( mmc_block_gendisk.part[minor].nr_sects > 0 )
++ dev->card = card;
++ }
++ __mmc_block_wrunlock_devices();
++out:
++error:
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++static void mmc_block_handle_request( void )
++{
++ struct request *request;
++ mmc_block_device_t dev;
++ mmc_card_t card;
++ char *buf;
++ loff_t pos;
++ unsigned int result = 0;
++
++ for (;;) {
++ int minor;
++
++ INIT_REQUEST;
++ request = CURRENT;
++ spin_unlock_irq( &io_request_lock );
++
++ minor = MINOR( request->rq_dev );
++ dev = __mmc_block_get_device( request->rq_dev );
++ if ( !dev ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "invalid device (%x:%x)\n",
++ MAJOR( request->rq_dev ), minor );
++
++ goto end_req;
++ }
++
++ card = dev->card;
++ (void)__mmc_block_put_device( dev );
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL2,
++// printk( KERN_INFO __FUNCTION__"(): "
++ "request %p: cmd %i sec %li (nr. %li)\n",
++ CURRENT, CURRENT->cmd, CURRENT->sector,
++ CURRENT->current_nr_sectors );
++
++ if ( request->current_nr_sectors >
++ mmc_block_gendisk.part[minor].nr_sects )
++ goto end_req;
++
++ // Handle the request
++ // TODO: handle clusterred requests in multiple block transfer mode
++ buf = request->buffer;
++ pos = (mmc_block_gendisk.part[minor].start_sect +
++ request->sector) * MMC_BLOCK_SECT_SIZE;
++
++ switch ( request->cmd )
++ {
++ int i, ret;
++
++ case READ:
++#if 0
++ ret = mmc_read( card,
++ (request->current_nr_sectors > 1) ?
++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE :
++ MMC_TRANSFER_MODE_BLOCK_SINGLE,
++ buf,
++ request->current_nr_sectors
++ * MMC_BLOCK_SECT_SIZE, /* FIXME */
++ &pos );
++ if ( ret < 0 )
++ goto end_req;
++
++#else
++ for ( i = 0;
++ i < request->current_nr_sectors;
++ i++ ) {
++ ret = mmc_read( card,
++ MMC_TRANSFER_MODE_BLOCK_SINGLE,
++ buf,
++ MMC_BLOCK_SECT_SIZE, /* FIXME */
++ &pos );
++ if ( ret < 0 )
++ goto end_req;
++ else
++ buf += ret;
++ }
++#endif
++ result = 1;
++ break;
++
++ case WRITE:
++ // TODO: Read only device
++#if 0
++ ret = mmc_write( card,
++ (request->current_nr_sectors > 1) ?
++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE :
++ MMC_TRANSFER_MODE_BLOCK_SINGLE,
++ buf,
++ request->current_nr_sectors
++ * MMC_BLOCK_SECT_SIZE, /* FIXME */
++ &pos );
++ if ( ret < 0 )
++ goto end_req;
++
++#else
++ for ( i = 0;
++ i < request->current_nr_sectors;
++ i++ ) {
++ ret = mmc_write( card,
++ MMC_TRANSFER_MODE_BLOCK_SINGLE,
++ buf,
++ MMC_BLOCK_SECT_SIZE, /* FIXME */
++ &pos );
++ if ( ret < 0 )
++ goto end_req;
++ else
++ buf += ret;
++ }
++#endif
++ result = 1;
++ break;
++ }
++
++end_req:
++ __LEAVE( "result=%d", result );
++ spin_lock_irq( &io_request_lock );
++ end_request( result );
++ }
++}
++
++static volatile int leaving = 0;
++static DECLARE_MUTEX_LOCKED( thread_sem );
++static DECLARE_WAIT_QUEUE_HEAD( thr_wq );
++static pid_t thr_id = -1;
++
++int mmc_block_thread( void *arg )
++{
++ struct task_struct *task = current;
++ DECLARE_WAITQUEUE(wait, task);
++
++ __ENTER0();
++
++ task->session = 1;
++ task->pgrp = 1;
++ task->flags |= PF_MEMALLOC;
++ strcpy( task->comm, "mmcblockd" );
++ task->tty = NULL;
++ spin_lock_irq( &task->sigmask_lock );
++ sigfillset( &task->blocked );
++ recalc_sigpending( task );
++ spin_unlock_irq( &task->sigmask_lock );
++ exit_mm( task );
++ exit_files( task );
++ exit_sighand( task );
++ exit_fs( task );
++
++ while ( !leaving ) {
++ add_wait_queue( &thr_wq, &wait);
++ set_current_state( TASK_INTERRUPTIBLE );
++ spin_lock_irq( &io_request_lock );
++ if ( QUEUE_EMPTY || QUEUE_PLUGGED ) {
++ spin_unlock_irq( &io_request_lock );
++ schedule();
++ remove_wait_queue( &thr_wq, &wait );
++ } else {
++ remove_wait_queue( &thr_wq, &wait );
++ set_current_state( TASK_RUNNING );
++ mmc_block_handle_request(); /* handle the request */
++ spin_unlock_irq( &io_request_lock );
++ }
++ }
++
++ up( &thread_sem );
++
++ __LEAVE0();
++ return 0;
++}
++
++#if LINUX_VERSION_CODE < 0x20300
++#define RQFUNC_ARG void
++#else
++#define RQFUNC_ARG request_queue_t *q
++#endif
++
++static void mmc_block_request( RQFUNC_ARG )
++{
++ wake_up( &thr_wq );
++}
++
++static int mmc_block_ioctl( struct inode * inode, struct file * file,
++ unsigned int cmd, unsigned long arg )
++{
++ int ret = -ENODEV;
++ mmc_block_device_t dev;
++ mmc_card_t card;
++ int minor;
++ __ENTER0();
++
++ if ( !inode || !file ) {
++ ret = -EINVAL;
++ goto error;
++ }
++ minor = MINOR( inode->i_rdev );
++
++ dev = __mmc_block_get_device( inode->i_rdev );
++ if ( !dev ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid device\n" );
++ goto error;
++ }
++
++ card = dev->card;
++ __mmc_block_put_device( dev );
++
++ switch ( cmd ) {
++ case BLKGETSIZE: /* Return device size */
++ {
++ unsigned long value;
++
++ __mmc_block_rdlock_devices();
++ value = mmc_block_gendisk.part[minor].nr_sects;
++ __mmc_block_rdunlock_devices();
++
++ if ( put_user( value, (unsigned long *) arg) ) {
++ ret = -EFAULT;
++ goto error;
++ }
++ }
++ break;
++
++#ifdef BLKGETSIZE64
++ case BLKGETSIZE64:
++ {
++ unsigned long value;
++
++ __mmc_block_rdlock_devices();
++ value = mmc_block_gendisk.part[minor].nr_sects;
++ __mmc_block_rdunlock_devices();
++
++ if ( put_user( (u64)value, (u64 *) arg) ) {
++ ret = -EFAULT;
++ goto error;
++ }
++ }
++ break;
++#endif
++
++ case HDIO_GETGEO:
++ {
++ struct hd_geometry geo;
++
++ ret = !access_ok( VERIFY_WRITE, arg, sizeof( geo ) );
++ if ( ret ) {
++ ret = -EFAULT;
++ goto error;
++ }
++
++ geo.heads = 1;
++ geo.sectors = 1;
++
++ __mmc_block_rdlock_devices();
++ geo.cylinders = mmc_block_gendisk.part[minor].nr_sects;
++ geo.start = mmc_block_gendisk.part[minor].start_sect;
++ __mmc_block_rdunlock_devices();
++
++ if ( copy_to_user( (int *)arg, &geo, sizeof( geo ) ) ) {
++ ret = -EFAULT;
++ goto error;
++ }
++ }
++ break;
++
++ case BLKRRPART:
++ if ( !capable( CAP_SYS_ADMIN ) ) {
++ ret = -EACCES;
++ goto error;
++ }
++ (void)mmc_block_revalidate( inode->i_rdev );
++ break;
++
++ default:
++ ret = blk_ioctl( inode->i_rdev, cmd, arg );
++ goto out;
++ }
++
++ ret = 0;
++error:
++out:
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++#if LINUX_VERSION_CODE < 0x20326
++static struct file_operations mmc_block_fops =
++{
++ open: mmc_block_open,
++ ioctl: mmc_block_ioctl,
++ release: mmc_block_release,
++ check_media_change: mmc_block_check_disk_change,
++ revalidate: mmc_block_revalidate,
++ read: block_read,
++ write: block_write
++};
++#else
++static struct block_device_operations mmc_block_fops =
++{
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
++ owner: THIS_MODULE,
++#endif
++ open: mmc_block_open,
++ release: mmc_block_release,
++ ioctl: mmc_block_ioctl,
++ check_media_change: mmc_block_check_disk_change,
++ revalidate: mmc_block_revalidate
++};
++#endif
++
++
++static int mmc_block_notify_add( mmc_card_t card )
++{
++ int ret = -1;
++ mmc_block_device_t dev;
++ kdev_t start;
++ int minor;
++
++ __ENTER0();
++
++ if ( !card || !card->ctrlr )
++ goto error;
++
++ start = MMC_BLOCK_MKDEV( card->ctrlr->slot, card->slot );
++ dev = &mmc_block_device[MINOR( start )];
++
++ __mmc_block_wrlock_devices();
++ if ( !dev->card ) {
++ dev->card = card;
++ ret = 0;
++ }
++ __mmc_block_wrunlock_devices();
++
++ if ( !ret ) {
++ int i;
++
++ /* allow to read partition table */
++ __mmc_block_rdlock_devices();
++ grok_partitions( &mmc_block_gendisk, MINOR( start ),
++ mmc_block_gendisk.max_p,
++ card->info.capacity>>9 /* sectors */
++ );
++ __mmc_block_rdunlock_devices();
++
++ __mmc_block_wrlock_devices();
++ for ( i = start + mmc_block_gendisk.max_p - 1; i >= 0; --i ) {
++ minor = MINOR( i );
++ dev = &mmc_block_device[minor];
++ if ( mmc_block_gendisk.part[minor].nr_sects > 0 )
++ dev->card = card;
++ }
++ __mmc_block_wrunlock_devices();
++ }
++error:
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++
++static int mmc_block_notify_remove( mmc_card_t card )
++{
++ int ret = -1;
++
++ __ENTER( "card=0x%p", card );
++
++ if ( card && card->ctrlr )
++ ret = __mmc_block_invalidate_card( card, FALSE );
++
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++static mmc_notifier_rec_t mmc_block_notifier = {
++ add: mmc_block_notify_add,
++ remove: mmc_block_notify_remove
++};
++
++static int __init mmc_block_module_init( void )
++{
++ int ret = -ENODEV;
++ int i;
++
++ __ENTER0();
++
++ init_rwsem( &mmc_block_device_sem );
++
++ if ( devfs_register_blkdev( MAJOR_NR, MAJOR_NAME, &mmc_block_fops ) ) {
++ MMC_ERROR( "Can't allocate major number %d for MMC block devices.\n", MMC_BLOCK_MAJOR );
++ ret = -EAGAIN;
++ goto error;
++ }
++
++ for ( i = 0; i < (1<<MINORBITS); i++ ) {
++ __mmc_block_device_init( i );
++ init_MUTEX( &mmc_block_device[i].sem );
++
++ /* We fill it in at open() time. */
++ mmc_block_blk_sizes[i] = 0;
++ mmc_block_blk_blksizes[i] = BLOCK_SIZE;
++ mmc_block_hardsect_sizes[i] = 0;
++ }
++
++ init_waitqueue_head( &thr_wq );
++ /* Allow the block size to default to BLOCK_SIZE. */
++ blksize_size[MAJOR_NR] = mmc_block_blk_blksizes;
++ hardsect_size[MAJOR_NR] = mmc_block_hardsect_sizes;
++ /* Gendisk stuff */
++ memset( mmc_block_partitions, 0, sizeof( mmc_block_partitions ) );
++ add_gendisk( &mmc_block_gendisk );
++
++/* FIXME: per controller request queue, I/O and card stack update threads */
++ blk_init_queue( BLK_DEFAULT_QUEUE( MAJOR_NR ), &mmc_block_request );
++ thr_id = kernel_thread( mmc_block_thread, NULL,
++ CLONE_FS|CLONE_FILES|CLONE_SIGHAND );
++
++ if ( !mmc_register( MMC_REG_TYPE_USER, &mmc_block_notifier, 0 ) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register with MMC core\n" );
++ goto error;
++ }
++
++ ret = 0;
++ goto out;
++error:
++ if ( thr_id != -1 ) {
++/* quit the thread */
++ leaving = 1;
++ wake_up(&thr_wq);
++
++ down(&thread_sem);
++ }
++ blksize_size[MAJOR_NR] = NULL;
++ blk_size[MAJOR_NR] = NULL;
++ hardsect_size[MAJOR_NR] = NULL;
++out:
++ __LEAVE0();
++ return ret;
++}
++
++static void __exit mmc_block_module_cleanup( void )
++{
++/* quit the thread */
++ leaving = 1;
++ wake_up(&thr_wq);
++
++ down(&thread_sem);
++
++ mmc_unregister( MMC_REG_TYPE_USER, &mmc_block_notifier );
++ del_gendisk( &mmc_block_gendisk );
++ devfs_unregister_blkdev( MAJOR_NR, MAJOR_NAME );
++
++ blk_cleanup_queue( BLK_DEFAULT_QUEUE( MAJOR_NR ) );
++ blksize_size[MAJOR_NR] = NULL;
++ blk_size[MAJOR_NR] = NULL;
++ hardsect_size[MAJOR_NR] = NULL;
++}
++
++EXPORT_NO_SYMBOLS;
++
++module_init( mmc_block_module_init );
++module_exit( mmc_block_module_cleanup );
++
++
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ linux-2.4.27/drivers/mmc/mmc_core.c
+@@ -0,0 +1,1124 @@
++/*
++ * linux/drivers/mmc/mmc_core.c
++ * MultiMediaCard subsystem core implementation
++ *
++ * Author: Vladimir Shebordaev
++ * Copyright: MontaVista Software Inc.
++ *
++ * $Id: mmc_core.c,v 0.3.1.14 2002/09/27 17:36:09 ted Exp ted $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++
++#include <linux/slab.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++
++#ifdef CONFIG_PM
++#include <linux/pm.h>
++#endif
++
++#include <mmc/types.h>
++#include <mmc/mmc.h>
++#include <mmc/ioctl.h>
++
++#include "types.h"
++
++#define __MMC_CORE_IMPLEMENTATION__
++#include "mmc.h"
++
++/* MMC controllers registered in the system */
++static mmc_controller_t mmc_controller[MMC_CONTROLLERS_MAX];
++static int mmc_ncontrollers = 0;
++static rwsemaphore_t mmc_controller_sem; /* controller table lock */
++#ifdef CONFIG_PM
++static struct pm_dev *mmc_pm_dev = NULL;
++#endif
++
++/* users' notification list */
++static mmc_notifier_t mmc_notifier = NULL;
++static rwsemaphore_t mmc_notifier_sem; /* notifiers' list lock */
++#ifdef CONFIG_PROC_FS
++static proc_dir_entry_t mmc_proc_dir = NULL;
++#endif
++
++/************************************************
++ * service function prototypes and declarations *
++ ************************************************/
++static inline int mmc_acquire_io( mmc_controller_t ctrlr, mmc_card_t card )
++{
++ int ret = -EIO;
++
++ __ENTER0();
++
++ if ( !card || !ctrlr ) {
++ ret = -EINVAL;
++ goto error;
++ }
++#ifdef CONFIG_HOTPLUG
++/* TODO: account for controller removal */
++#endif
++ down( &ctrlr->io_sem );
++#if 0
++ down_read( &ctrlr->update_sem ); /* FIXME */
++ if ( card->state != MMC_CARD_STATE_UNPLUGGED )
++ ret = 0;
++ up_read( &ctrlr->update_sem );
++
++ if ( ret )
++ up( &ctrlr->io_sem );
++#else
++ ret = 0;
++#endif
++
++error:
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++static inline void mmc_release_io( mmc_controller_t ctrlr, mmc_card_t card )
++{
++ __ENTER0();
++#ifdef CONFIG_HOTPLUG
++/* TODO: account for controller removal */
++#endif
++ if ( !card && !ctrlr ) { /* FIXME */
++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "bad card reference\n" );
++ goto error;
++ }
++ up( &ctrlr->io_sem );
++error:
++ __LEAVE0();
++}
++
++/* TODO: there should be a separate context to be awaken
++ * by the card intertion interrupt; called under ctrlr->update_sem
++ * held down by now */
++static int __mmc_update_card_stack( mmc_controller_t ctrlr )
++{
++ int ret = -1;
++ mmc_card_t card, prev;
++
++ __ENTER0();
++
++ if ( !ctrlr || !ctrlr->tmpl )
++ goto error;
++
++ /* check unplugged cards first... */
++ if ( (ret = ctrlr->tmpl->check_card_stack( ctrlr )) )
++ goto error;
++
++ /* unregister unplugged cards and free 'em immediately */
++ if ( ctrlr->stack.ncards > 0 ) {
++ prev = ctrlr->stack.first;
++ /* process the stack tail first */
++ if ( prev->next ) {
++ card = prev->next;
++ while ( card ) {
++ if ( card->state == MMC_CARD_STATE_UNPLUGGED ) {
++ if ( ctrlr->stack.selected == card )
++ ctrlr->stack.selected = NULL;
++#ifdef CONFIG_PROC_FS
++ if ( card->proc ) {
++ remove_proc_entry( card->proc_name, ctrlr->proc );
++ card->proc = NULL;
++ }
++#endif
++ ctrlr->slot_next = card->slot; /* FIXME */
++ prev->next = card->next;
++ if ( ctrlr->stack.last == card )
++ ctrlr->stack.last = prev;
++ /* FIXME: controller use count */
++ mmc_notify_remove( card );
++ --ctrlr->stack.ncards;
++ if ( (ctrlr->usage > 0) && ctrlr->tmpl->owner ) {
++ --ctrlr->usage;
++ MMC_DEBUG( MMC_DEBUG_LEVEL2,
++ "'%s' use count "
++ "decreased (%d)\n",
++ ctrlr->tmpl->name,
++ ctrlr->usage );
++ __MOD_DEC_USE_COUNT(
++ ctrlr->tmpl->owner );
++ }
++ __mmc_card_free( card );
++
++ card = prev->next;
++ }
++ }
++ }
++ /* then the head */
++ card = ctrlr->stack.first;
++ if ( card && (card->state == MMC_CARD_STATE_UNPLUGGED) ) {
++ if ( ctrlr->stack.selected == card )
++ ctrlr->stack.selected = NULL;
++#ifdef CONFIG_PROC_FS
++ if ( card->proc ) {
++ remove_proc_entry( card->proc_name, ctrlr->proc );
++ card->proc = NULL;
++ }
++#endif
++ ctrlr->slot_next = card->slot; /* FIXME */
++ mmc_notify_remove( card ); /* FIXME: should unregister here */
++ ctrlr->stack.first = card->next;
++ if ( ctrlr->stack.last == card )
++ ctrlr->stack.last = NULL;
++ /* FIXME: controller use count */
++ --ctrlr->stack.ncards;
++ if ( (ctrlr->usage > 0) && ctrlr->tmpl->owner ) {
++ --ctrlr->usage;
++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "'%s' use count "
++ "decreased (%d)\n", ctrlr->tmpl->name,
++ ctrlr->usage );
++ __MOD_DEC_USE_COUNT( ctrlr->tmpl->owner );
++ }
++ __mmc_card_free( card );
++ }
++ }
++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "after stack check: ncards=%d"
++ " first=0x%x last=0x%x\n", ctrlr->stack.ncards,
++ ctrlr->stack.first, ctrlr->stack.last );
++ /* ...then add newly inserted ones */
++ if ( (ret = ctrlr->tmpl->update_acq( ctrlr )) )
++ goto error;
++ /* ret = 0; */
++error:
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++/*
++ * 1) check error code returned by controller; it's up to
++ * controller to detect error conditions reported by the card
++ * and to abort data transfer requests properly (e.g. send
++ * CMD12(STOP_TRANSMISSION) to abort ADDRESS_ERROR multiple
++ * block transfers)
++ * 2) arrange for card stack update when necessary
++ * (all pending i/o requests must be held pending,
++ * update procedure must start immediately after
++ * error has been detected)
++ */
++static inline int __mmc_check_error( mmc_card_t card, int err )
++{
++ int ret = -EIO;
++ mmc_controller_t ctrlr;
++
++ __ENTER0();
++
++ if ( !card || !card->ctrlr )
++ goto error;
++
++ ctrlr = card->ctrlr;
++
++ if ( err < 0 ) {
++ switch ( err ) {
++ /* bus error occurred */
++ case MMC_ERROR_CRC_WRITE_ERROR:
++ case MMC_ERROR_CRC_READ_ERROR:
++ case MMC_ERROR_RES_CRC_ERROR:
++ case MMC_ERROR_READ_TIME_OUT:
++ case MMC_ERROR_TIME_OUT_RESPONSE:
++ down_write( &ctrlr->update_sem ); /* FIXME */
++ if ( !__mmc_update_card_stack( ctrlr ) )
++ ret = -ENXIO;
++ up_write( &ctrlr->update_sem );
++ break;
++ }
++ } else
++ ret = err;
++error:
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++static inline void __mmc_free_controller( mmc_controller_t ctrlr )
++{
++ if ( ctrlr ) {
++ if ( ctrlr->stack.ncards > 0 )
++ __mmc_card_stack_free( &ctrlr->stack );
++ kfree( ctrlr );
++ }
++}
++
++#ifdef CONFIG_PROC_FS
++static int mmc_proc_read_card_info( char *page, char **start, off_t off, int count, int *eof, void *data )
++{
++ int ret = -EINVAL;
++ mmc_card_t card = (mmc_card_t)data;
++ char *cp = page;
++
++ if ( !card )
++ goto error;
++
++ down_read( &card->ctrlr->update_sem );
++/* TODO: proc report
++ * Type: RO, RW or IO (by CCC)
++ * MID: 0x%02x card->info.cid.mid
++ * OID: 0x%04x card->info.cid.oid
++ * PNM: %s card->info.pnm
++ * PRV: %s card->info.prv
++ * PSN: 0x%08x card->info.cid.psn
++ * MDT: %s card->info.mdt
++ * Capacity: card->info.capacity (Bytes)
++ */
++#if 1
++ cp += sprintf( cp, "Capacity: %dKb.\n\n", (card->info.capacity>>10) );
++#else /* TODO */
++ cp += sprintf( cp, "Type : %s\n", card->info.type );
++ cp += sprintf( cp, "MID : 0x%02x\n", card->info.cid.mid );
++ cp += sprintf( cp, "OID : 0x%04x\n", card->info.cid.oid );
++ cp += sprintf( cp, "PNM : %s\n", card->info.pnm );
++ cp += sprintf( cp, "PRV : %s\n", card->info.prv );
++ cp += sprintf( cp, "PSN : 0x%08x\n", card->info.cid.psn );
++ cp += sprintf( cp, "MDT : %s\n", card->info.mdt );
++ cp += sprintf( cp, "Capacity: %dKB\n",
++ (card->info.capacity>>10) );
++#endif
++ up_read( &card->ctrlr->update_sem );
++
++ ret = cp - page;
++error:
++ return ret;
++}
++#endif
++
++/*************************************
++ * MMC core interface implementation *
++ *************************************/
++int mmc_notify_add( mmc_card_t card )
++{
++ int ret = 0;
++ mmc_notifier_t notifier;
++
++ __ENTER0();
++ if ( card ) {
++ for ( notifier = mmc_notifier; notifier;
++ notifier = notifier->next )
++ if ( notifier->add )
++ if ( (ret = notifier->add( card )) )
++ break;
++ }
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++EXPORT_SYMBOL( mmc_notify_add );
++
++int mmc_notify_remove( mmc_card_t card )
++{
++ int ret = 0;
++ mmc_notifier_t notifier;
++
++ __ENTER0();
++ if ( card ) {
++ for ( notifier = mmc_notifier; notifier;
++ notifier = notifier->next )
++ if ( notifier->remove )
++ if ( (ret = notifier->remove( card )) )
++ break;
++ }
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++EXPORT_SYMBOL( mmc_notify_remove );
++
++int mmc_update_card_stack( int host )
++{
++ int ret = -EINVAL;
++ mmc_controller_t ctrlr;
++
++ __ENTER0();
++
++ if ( (host < 0) || (host >= MMC_CONTROLLERS_MAX) )
++ goto error;
++
++ down_read( &mmc_controller_sem );
++ if ( (ctrlr = mmc_controller[host]) ) {
++ down_write( &ctrlr->update_sem );
++ (void)__mmc_update_card_stack( ctrlr );
++ up_write( &ctrlr->update_sem );
++ }
++ up_read( &mmc_controller_sem );
++ ret = 0;
++error:
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++EXPORT_SYMBOL( mmc_update_card_stack );
++
++ssize_t mmc_read( mmc_card_t card, mmc_transfer_mode_t mode, char *buf, size_t size, loff_t *paddr )
++{
++ ssize_t ret = -EIO;
++ mmc_controller_t ctrlr;
++ mmc_data_transfer_req_rec_t transfer;
++
++ if ( !paddr ) {
++ ret = -EINVAL;
++ goto error;
++ }
++
++ if ( !card ) {
++ ret = -ENODEV;
++ goto error;
++ }
++
++ __ENTER( "card=%p usage=%d mode=%d buf=%p size=%d addr=%x",
++ card, card->usage, mode, buf, size, *paddr );
++
++ ctrlr = card->ctrlr;
++ if ( (ret = mmc_acquire_io( ctrlr, card )) )
++ goto error;
++
++ memset( &transfer, 0, sizeof( mmc_data_transfer_req_rec_t ) );
++ transfer.cmd = MMC_READ;
++ transfer.mode = mode;
++ transfer.type = MMC_USER; /* FIXME: buffer cache */
++ transfer.buf = buf;
++ transfer.addr = *paddr;
++ transfer.cnt = size;
++
++/* max block size defined by CSD[read_bl_len] */
++ transfer.blksz = card->info.read_bl_len;
++ transfer.nob = size / transfer.blksz;
++ if ( (size - (transfer.nob * transfer.blksz)) > 0 )
++ transfer.nob++;
++
++/* TODO: controller may restrict maximum block size; set block size
++ * and number of blocks that their accumulated length fit to
++ * CSD[READ_BL_LEN] not to bother with block misalignment in multiple
++ * block transfers */
++ ctrlr = card->ctrlr;
++ if ( transfer.blksz > ctrlr->tmpl->block_size_max ) {
++ ret = -EINVAL; /* FIXME */
++ goto error;
++ }
++
++ if ( ctrlr->stack.selected != card ) {
++ if ( (ret = ctrlr->tmpl->setup_card( ctrlr, card )) )
++ goto err_mmc;
++ ctrlr->stack.selected = card;
++ }
++
++ switch( mode ) {
++ case MMC_TRANSFER_MODE_STREAM:
++ if ( !ctrlr->tmpl->stream_read ) {
++ ret = -ENXIO;
++ goto err_down;
++ }
++/* TODO: The max clock frequency for stream read operation is given by
++ the following formula:
++ max speed = min ( TRAN_SPEED, 8*2^(READ_BL_LEN) - NSAC/TAAC )
++
++ If the card is not able to sustain data transfer it will set the
++ UNDERRUN error bit in the status register, abort the transmission
++ and wait in the Data state for a stop command
++ */
++ ret = ctrlr->tmpl->stream_read( ctrlr, &transfer );
++ break;
++
++ case MMC_TRANSFER_MODE_BLOCK_SINGLE:
++ if ( !ctrlr->tmpl->read_block ) {
++ ret = -ENXIO;
++ goto err_down;
++ }
++/* TODO: buffer size and data alignment (v3.4, p.29):
++ if CSD[READ_BL_PARTIAL] is set, smaller blocks whose starting
++ and ending address are entirely contained within one physical
++ block (as defined by CSD[READ_BL_LEN]) may also be transmitted
++ */
++ transfer.type = MMC_KERNEL; /* FIXME */
++ ret = ctrlr->tmpl->read_block( ctrlr, &transfer );
++ break;
++
++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE:
++ if ( !ctrlr->tmpl->read_mblock ) {
++ ret = -ENXIO;
++ goto err_down;
++ }
++
++ if ( transfer.nob > ctrlr->tmpl->nob_max ) {
++ ret = -EINVAL;
++ goto error;
++ }
++/* TODO: buffer size and data alignment (v3.4, p.29):
++ if the host uses patrial blocks whose accumulated length is
++ not block aligned and block misalignment is not allowed, the
++ card should detect a block misalignment error condition at the
++ beginning of the first misaligned block
++ */
++ transfer.type = MMC_KERNEL; /* FIXME */
++ ret = ctrlr->tmpl->read_mblock( card->ctrlr, &transfer );
++ break;
++
++ default:
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "request for unknown transfer type\n" );
++ ret = -EINVAL;
++ }
++err_mmc:
++ ret = __mmc_check_error( card, ret );
++ if ( ret >= 0 ) {
++ ret = size - transfer.cnt;
++ *paddr += ret;
++ }
++err_down:
++ mmc_release_io( ctrlr, card );
++error:
++ __LEAVE("ret=%d", ret);
++ return ret;
++}
++EXPORT_SYMBOL( mmc_read );
++
++ssize_t mmc_write( mmc_card_t card, mmc_transfer_mode_t mode, const char *buf, size_t size, loff_t *paddr )
++{
++ ssize_t ret = -ESPIPE;
++ mmc_controller_t ctrlr;
++ mmc_data_transfer_req_rec_t transfer;
++
++ if ( !paddr ) {
++ ret = -EINVAL;
++ goto error;
++ }
++
++ if ( !card ) {
++ ret = -ENODEV;
++ goto error;
++ }
++
++ __ENTER( "card=%p usage=%d mode=%d buf=%p size=%d addr=%llx",
++ card, card->usage, mode, buf, size, *paddr );
++
++ ctrlr = card->ctrlr;
++ if ( (ret = mmc_acquire_io( ctrlr, card )) )
++ goto error;
++
++ memset( &transfer, 0, sizeof( mmc_data_transfer_req_rec_t ) );
++ transfer.cmd = MMC_WRITE;
++ transfer.mode = mode;
++ transfer.type = MMC_USER; /* FIXME: buffer cache */
++ transfer.buf = (char *)buf;
++ transfer.addr = *paddr;
++ transfer.cnt = size;
++
++/* max block size defined by CSD[write_bl_len] */
++ transfer.blksz = card->info.write_bl_len;
++ transfer.nob = size / transfer.blksz;
++ if ( (size - (transfer.nob * transfer.blksz)) > 0 )
++ transfer.nob++;
++
++/* TODO: controller may restrict maximum block size; set block size
++ * and number of blocks that their accumulated length fit to
++ * CSD[WRITE_BL_LEN] not to bother with block misalignment in multiple
++ * block transfers */
++ ctrlr = card->ctrlr;
++ if ( transfer.blksz > ctrlr->tmpl->block_size_max ) {
++ ret = -EINVAL; /* FIXME */
++ goto error;
++ }
++
++ if ( ctrlr->stack.selected != card ) {
++ if ( (ret = ctrlr->tmpl->setup_card( ctrlr, card )) )
++ goto err_mmc;
++ ctrlr->stack.selected = card;
++ }
++
++ transfer.cmd = MMC_WRITE;
++ transfer.mode = mode;
++ transfer.type = MMC_USER;
++ switch( mode ) {
++ case MMC_TRANSFER_MODE_STREAM:
++ if ( !ctrlr->tmpl->stream_write ) {
++ ret = -ENXIO;
++ goto err_down;
++ }
++ ret = ctrlr->tmpl->stream_write( ctrlr, &transfer );
++ break;
++
++ case MMC_TRANSFER_MODE_BLOCK_SINGLE:
++ if ( !ctrlr->tmpl->write_block ) {
++ ret = -ENXIO;
++ goto err_down;
++ }
++ transfer.type = MMC_KERNEL; /* FIXME */
++ ret = ctrlr->tmpl->write_block( ctrlr, &transfer );
++ break;
++
++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE:
++ if ( !ctrlr->tmpl->write_mblock ) {
++ ret = -ENXIO;
++ goto err_down;
++ }
++ transfer.type = MMC_KERNEL; /* FIXME */
++ ret = ctrlr->tmpl->write_mblock( card->ctrlr, &transfer );
++ break;
++
++ default:
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "request for unknown transfer type\n" );
++ }
++
++err_mmc:
++ ret = __mmc_check_error( card, ret ); /* FIXME */
++ if ( ret >= 0 ) {
++ ret = size - transfer.cnt;
++ *paddr += ret;
++ }
++err_down:
++ mmc_release_io( ctrlr, card );
++error:
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++EXPORT_SYMBOL( mmc_write );
++
++int mmc_ioctl( mmc_card_t card, unsigned int cmd, unsigned long arg )
++{
++ int ret = -EINVAL;
++ mmc_controller_t ctrlr;
++
++ if ( !card ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad card reference\n" )
++ goto error;
++ }
++
++ ctrlr = card->ctrlr;
++ if ( mmc_acquire_io( ctrlr, card ) ) {
++ ret = -ENXIO;
++ goto error;
++ }
++
++ switch ( cmd ) {
++ case IOCMMCGCARDESC:
++ if ( copy_to_user( (void *)arg, &card->info, sizeof( mmc_card_info_rec_t ) ) )
++ ret = -EFAULT;
++ break;
++/*
++ * 1. TODO: erase region
++ * 2. TODO: set/unset write protection, lock/password
++ */
++ default:
++ ret = -ENOIOCTLCMD;
++ }
++
++ mmc_release_io( ctrlr, card );
++error:
++ return ret;
++}
++EXPORT_SYMBOL( mmc_ioctl );
++
++/*
++ * registry stuff
++ */
++mmc_card_t mmc_get_card( int host, int slot )
++{
++ mmc_card_t ret = NULL;
++ mmc_controller_t ctrlr = NULL;
++ int found;
++
++ __ENTER( "host=%d, card=%d", host, slot );
++
++ if ( ((host < 0) || (host >= MMC_CONTROLLERS_MAX))
++ && ((slot < 0) || (slot >= MMC_CARDS_MAX)) )
++ goto error;
++
++ down_read( &mmc_controller_sem );
++
++ if ( (ctrlr = mmc_controller[host]) ) {
++ down_write( &ctrlr->update_sem );
++ if ( ctrlr->stack.ncards > 0 ) {
++ ret = ctrlr->stack.first;
++ found = FALSE;
++ while ( ret ) {
++ if ( (ret->slot == slot) && (ret->state !=
++ MMC_CARD_STATE_UNPLUGGED) ) {
++ found = TRUE;
++ break;
++ }
++ ret = ret->next;
++ }
++
++ if ( found ) {
++ if ( ctrlr->tmpl->owner ) {
++ ++ctrlr->usage;
++ MMC_DEBUG( MMC_DEBUG_LEVEL2,
++ "'%s' use count increased (%d)\n",
++ ctrlr->tmpl->name, ctrlr->usage );
++ __MOD_INC_USE_COUNT( ctrlr->tmpl->owner );
++ }
++ ++ret->usage;
++ } else
++ ret = NULL;
++ }
++ up_write( &ctrlr->update_sem );
++ }
++ up_read( &mmc_controller_sem );
++error:
++ __LEAVE("ret=0x%p usage=%d", ret, ret ? ret->usage : -1 );
++ return ret;
++}
++EXPORT_SYMBOL( mmc_get_card );
++
++void mmc_put_card( mmc_card_t card )
++{
++ mmc_card_t tmp = NULL;
++ mmc_controller_t ctrlr;
++ int found;
++
++ __ENTER( "card=0x%p", card );
++
++ if ( !card )
++ goto error;
++
++ ctrlr = card->ctrlr;
++
++ down_read( &mmc_controller_sem );
++ if ( !ctrlr || (ctrlr != mmc_controller[ctrlr->slot]) ) {
++ MMC_ERROR( "bad controller reference: ctrlr=0x%p\n", ctrlr );
++ goto err_down;
++ }
++
++ down_write( &ctrlr->update_sem );
++ if ( ctrlr->stack.ncards > 0 ) {
++ tmp = ctrlr->stack.first;
++ found = FALSE;
++ while ( tmp ) {
++ if ( tmp == card ) {
++ found = TRUE;
++ break;
++ }
++ tmp = tmp->next;
++ }
++
++ if ( found ) {
++ if ( tmp->usage > 0 ) {
++ --tmp->usage;
++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "usage=%d"
++ "owner=0x%p\n", tmp->usage,
++ ctrlr->tmpl->owner );
++ if ( !tmp->usage && (ctrlr->usage > 0)
++ && ctrlr->tmpl->owner ) {
++ --ctrlr->usage;
++ MMC_DEBUG( MMC_DEBUG_LEVEL2,
++ "'%s' use count "
++ "decreased (%d)\n",
++ ctrlr->tmpl->name,
++ ctrlr->usage );
++ __MOD_DEC_USE_COUNT(
++ ctrlr->tmpl->owner );
++ }
++ }
++ } else
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad card reference\n" );
++
++ }
++ up_write( &ctrlr->update_sem );
++err_down:
++ up_read( &mmc_controller_sem );
++error:
++ __LEAVE( "found=%d", found );
++ return;
++}
++EXPORT_SYMBOL( mmc_put_card );
++
++static inline void *mmc_register_user( mmc_notifier_t notifier )
++{
++ mmc_notifier_t ret = NULL, last = mmc_notifier;
++
++ MOD_INC_USE_COUNT;
++ if ( notifier ) {
++ down_write( &mmc_notifier_sem );
++
++ notifier->next = NULL;
++ if ( !last ) {
++ mmc_notifier = notifier;
++ ret = notifier;
++ } else {
++ while ( last->next ) {
++ if ( last == notifier ) {
++ MOD_DEC_USE_COUNT;
++ break;
++ }
++ last = last->next;
++ }
++ if ( last != notifier ) {
++ last->next = notifier;
++ ret = notifier;
++ }
++ }
++ up_write( &mmc_notifier_sem );
++ }
++/* notify new user about the cards present in the system */
++ if ( ret && ret->add ) {
++ int i;
++
++ down_read( &mmc_controller_sem );
++ for ( i = 0; i < mmc_ncontrollers; i++ ) {
++ mmc_controller_t ctrlr = mmc_controller[i];
++
++ down_read( &ctrlr->update_sem ); /* FIXME */
++ __mmc_card_stack_foreach( &ctrlr->stack,
++ ret->add, FALSE );
++ up_read( &ctrlr->update_sem ); /* FIXME */
++ }
++ up_read( &mmc_controller_sem );
++ }
++/* error: */
++ __LEAVE( "mmc_notifier=0x%p, mmc_notifier->next=0x%p",
++ mmc_notifier, mmc_notifier ? mmc_notifier->next : NULL );
++ return ret;
++}
++
++static inline mmc_controller_t mmc_register_controller( mmc_controller_tmpl_t tmpl, size_t extra )
++{
++ mmc_controller_t ret = NULL;
++ int found;
++ int i;
++
++ MOD_INC_USE_COUNT;
++
++ down_write( &mmc_controller_sem );
++
++ if ( mmc_ncontrollers >= MMC_CONTROLLERS_MAX ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "there're too many controllers\n" );
++ goto error;
++ }
++
++ found = FALSE;
++ for ( i = 0; i < MMC_CONTROLLERS_MAX; i++ )
++ if ( !mmc_controller[i] ) {
++ found = TRUE;
++ break;
++ }
++
++ if ( !found ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "there're no empty slots\n" );
++ goto error;
++ }
++
++ if ( !tmpl->init ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'init()'\n" );
++ goto error;
++ }
++
++ if ( !tmpl->probe ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'probe()'\n" );
++ goto error;
++ }
++
++ if ( !tmpl->init_card_stack ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'init_card_stack()'\n" );
++ goto error;
++ }
++
++ if ( !tmpl->update_acq ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'update_acq()'\n" );
++ goto error;
++ }
++
++ if ( !tmpl->check_card_stack ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'check_card_stack()'\n" );
++ goto error;
++ }
++
++ if ( !tmpl->setup_card ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'setup_card()'\n" );
++ goto error;
++ }
++
++ ret = kmalloc( sizeof( mmc_controller_rec_t ) + extra, GFP_ATOMIC ); /* FIXME: ISA + GFP_DMA */
++ if ( !ret ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "out of memory\n" );
++ goto error;
++ }
++
++ memset( ret, 0, sizeof( mmc_controller_rec_t ) + extra );
++
++ if ( (tmpl->probe( ret ) != 1) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "controller probe failed\n" );
++ goto err_free;
++ }
++
++ if ( tmpl->init( ret ) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "controller initialization failure\n" );
++ goto err_free;
++ }
++
++ ret->state = MMC_CONTROLLER_FOUND;
++ ret->slot = i;
++ ret->tmpl = tmpl;
++ init_MUTEX( &ret->io_sem );
++ init_rwsem( &ret->update_sem );
++#ifdef CONFIG_PROC_FS
++ if ( mmc_proc_dir ) {
++ snprintf( ret->proc_name, sizeof( ret->proc_name ),
++ "host%d", ret->slot );
++ ret->proc = proc_mkdir( ret->proc_name, mmc_proc_dir );
++ }
++#endif
++
++/* initialize card stack */
++ if ( ret->tmpl->init_card_stack( ret ) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "card stack initialization failure\n" );
++ if ( ret->tmpl->remove )
++ ret->tmpl->remove( ret ); /* FIXME */
++ goto err_free;
++ }
++
++ mmc_controller[ret->slot] = ret;
++ ++mmc_ncontrollers;
++
++/* notify users */
++ if ( ret->stack.ncards > 0 ) {
++ down_read( &mmc_notifier_sem );
++ if ( (i = __mmc_card_stack_foreach( &ret->stack, mmc_notify_add, FALSE ) ) < 0 )
++ MMC_ERROR( "device add notification failed at slot %d\n", -i );
++ up_read( &mmc_notifier_sem );
++ }
++ goto out;
++
++err_free:
++#ifdef CONFIG_PROC_FS
++ if ( ret->proc )
++ remove_proc_entry( ret->proc_name, mmc_proc_dir );
++#endif
++ kfree( ret );
++error:
++ ret = NULL;
++ MOD_DEC_USE_COUNT;
++out:
++ up_write( &mmc_controller_sem );
++ return ret;
++}
++
++static inline mmc_card_t mmc_register_card( mmc_card_t card )
++{
++ mmc_card_t ret = NULL;
++ mmc_controller_t ctrlr;
++
++ if ( !card || !card->ctrlr )
++ goto error;
++
++ ctrlr = card->ctrlr;
++#ifdef CONFIG_PROC_FS
++ if ( ctrlr->proc ) {
++ snprintf( card->proc_name, sizeof( card->proc_name ),
++ "card%d", card->slot );
++ card->proc = create_proc_read_entry( card->proc_name,
++ 0444, ctrlr->proc,
++ mmc_proc_read_card_info, card );
++ }
++#endif
++ mmc_notify_add( card );
++error:
++ return ret;
++}
++
++void *mmc_register( mmc_reg_type_t reg_type, void *tmpl, size_t extra )
++{
++ void *ret = NULL;
++
++ switch ( reg_type ) {
++ case MMC_REG_TYPE_CARD:
++ ret = mmc_register_card( (mmc_card_t)tmpl );
++ break;
++
++ case MMC_REG_TYPE_USER:
++ ret = mmc_register_user( (mmc_notifier_t)tmpl );
++ break;
++
++ case MMC_REG_TYPE_HOST:
++ ret = mmc_register_controller( (mmc_controller_tmpl_t)tmpl, extra );
++ break;
++
++ default:
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "register request for unknown type\n" );
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL( mmc_register );
++
++static inline void mmc_unregister_user( mmc_notifier_t notifier )
++{
++ mmc_notifier_t prev = mmc_notifier;
++ int found = FALSE;
++
++ if ( notifier ) {
++ down_write( &mmc_notifier_sem );
++
++ if ( mmc_notifier == notifier) {
++ mmc_notifier = prev->next;
++ found = TRUE;
++
++ } else if ( mmc_notifier ) {
++ while( prev ) {
++ if ( prev->next == notifier ) {
++ found = TRUE;
++ prev->next = prev->next->next;
++ break;
++ }
++ prev = prev->next;
++ }
++ }
++
++ if ( found ) {
++ if ( notifier->remove ) {
++ int i;
++
++ down_read( &mmc_controller_sem );
++ for ( i = 0; i < mmc_ncontrollers; i++ ) {
++ mmc_controller_t ctrlr =
++ mmc_controller[i];
++
++ down_read( &ctrlr->update_sem );
++ __mmc_card_stack_foreach( &ctrlr->stack, notifier->remove, FALSE );
++ up_read( &ctrlr->update_sem );
++ }
++ up_read( &mmc_controller_sem );
++ }
++ }
++
++ up_write( &mmc_notifier_sem );
++ }
++
++ MOD_DEC_USE_COUNT;
++}
++
++static inline void mmc_unregister_controller( mmc_controller_t ctrlr )
++{
++ if ( !ctrlr || (mmc_controller[ctrlr->slot] != ctrlr ) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad unregister request\n" );
++ goto error;
++ }
++
++ down_write( &mmc_controller_sem );
++
++/* notify users */
++ if ( ctrlr->stack.ncards > 0 ) {
++ int slot;
++
++ down_read( &mmc_notifier_sem );
++ if ( (slot = __mmc_card_stack_foreach( &ctrlr->stack, mmc_notify_remove, FALSE ) ) )
++ MMC_ERROR( "device remove notification failed at slot %d\n", -slot );
++ up_read( &mmc_notifier_sem );
++ }
++
++#ifdef CONFIG_PROC_FS
++ if ( ctrlr->proc )
++ remove_proc_entry( ctrlr->proc_name, mmc_proc_dir );
++#endif
++
++ if ( ctrlr->tmpl && ctrlr->tmpl->remove )
++ ctrlr->tmpl->remove( ctrlr );
++
++ mmc_controller[ctrlr->slot] = NULL;
++ --mmc_ncontrollers;
++
++ __mmc_free_controller( ctrlr );
++
++ up_write( &mmc_controller_sem );
++ MOD_DEC_USE_COUNT;
++error:
++ return;
++}
++
++void mmc_unregister( mmc_reg_type_t reg_type, void *tmpl )
++{
++ switch ( reg_type ) {
++ case MMC_REG_TYPE_USER:
++ mmc_unregister_user( (mmc_notifier_t)tmpl );
++ break;
++
++ case MMC_REG_TYPE_HOST:
++ mmc_unregister_controller( (mmc_controller_t)tmpl );
++ break;
++
++ default:
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "unregister request for unknown type\n" );
++ }
++}
++EXPORT_SYMBOL( mmc_unregister );
++
++#ifdef CONFIG_PM
++/* power management support */
++static int mmc_pm_callback( struct pm_dev *pmdev, pm_request_t pmreq, void *pmdata )
++{
++ int ret = -EINVAL;
++ mmc_controller_t ctrlr;
++ int i;
++
++ __ENTER( "pmreq=%d", pmreq );
++
++ down_read( &mmc_controller_sem );
++
++ switch ( pmreq ) {
++ case PM_SUSPEND:
++ for ( ret = 0, i = 0; !ret && (i < mmc_ncontrollers); i++ ) {
++ ctrlr = mmc_controller[i];
++ if ( ctrlr->tmpl->suspend )
++ ret = ctrlr->tmpl->suspend( ctrlr );
++ }
++ if ( !ret )
++ break;
++
++ case PM_RESUME:
++ for ( i = mmc_ncontrollers - 1; i >= 0; i-- ) {
++ ctrlr = mmc_controller[i];
++ if ( ctrlr->tmpl->resume )
++ ctrlr->tmpl->resume( ctrlr );
++ }
++ ret = 0;
++ break;
++
++ default:
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "unsupported PM request %d\n",
++ pmreq );
++ }
++
++ up_read( &mmc_controller_sem );
++/* error: */
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++#endif
++
++/* kernel module stuff */
++static int __init mmc_core_module_init( void )
++{
++ int ret = -ENODEV;
++
++ memset( &mmc_controller, 0, sizeof( mmc_controller ) );
++
++ init_rwsem( &mmc_controller_sem );
++ init_rwsem( &mmc_notifier_sem );
++#ifdef CONFIG_PM
++ if ( !(mmc_pm_dev = pm_register( PM_UNKNOWN_DEV, 0, mmc_pm_callback )) ) MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register PM callback\n" );
++#endif
++#ifdef CONFIG_PROC_FS
++ mmc_proc_dir = proc_mkdir( "mmc", NULL );
++#endif
++ ret = 0;
++/* error: */
++ return ret;
++}
++
++static void __exit mmc_core_module_cleanup( void )
++{
++#ifdef CONFIG_PROC_FS
++ if ( mmc_proc_dir )
++ remove_proc_entry( "mmc", NULL );
++#endif
++#ifdef CONFIG_PM
++ pm_unregister( mmc_pm_dev );
++#endif
++}
++
++module_init( mmc_core_module_init );
++module_exit( mmc_core_module_cleanup );
++
++MODULE_LICENSE( "GPL" );
++
+--- /dev/null
++++ linux-2.4.27/drivers/mmc/mmc_pxa.c
+@@ -0,0 +1,1902 @@
++/*
++ * linux/drivers/mmc/mmc_pxa.c
++ * driver for Cotulla MMC controller
++ *
++ * Authors: Vladimir Shebordaev, Igor Oblakov
++ * Copyright: MontaVista Software Inc.
++ *
++ * $Id: mmc_pxa.c,v 0.3.1.12 2002/09/25 19:25:48 ted Exp ted $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/dma.h>
++
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++
++#include <mmc/types.h>
++#include <mmc/mmc.h>
++#include <mmc/ioctl.h>
++
++#include "types.h"
++#include "mmc.h"
++#include "mmc_pxa.h"
++
++static mmc_controller_t host = NULL;
++
++/* service routines */
++static inline int pxa_mmc_check_state( mmc_controller_t ctrlr, pxa_mmc_state_t state )
++{
++ int ret = -1;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++
++ if ( hostdata->state != state ) {
++ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "state (%s vs %s)\n", PXA_MMC_STATE_LABEL( hostdata->state ), PXA_MMC_STATE_LABEL( state ) );
++ goto error;
++ }
++ ret = 0;
++error:
++ return ret;
++}
++
++static inline void pxa_mmc_set_state( mmc_controller_t ctrlr, pxa_mmc_state_t state )
++{
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++
++ hostdata->state = state;
++}
++
++static inline int pxa_mmc_init_completion( mmc_controller_t ctrlr, u32 mask )
++{
++ int ret = -1;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++
++ if ( xchg( &hostdata->busy, 1 ) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "another interrupt "
++ "is already been expected\n" );
++ goto error;
++ }
++
++#if CONFIG_MMC_DEBUG_IRQ
++ hostdata->irqcnt = 1000;
++#endif
++ init_completion( &hostdata->completion );
++
++ MMC_I_MASK = MMC_I_MASK_ALL & ~mask;
++ ret = 0;
++error:
++ return ret;
++}
++
++#if CONFIG_MMC_DEBUG_IRQ
++static struct timer_list timer;
++static void wait_timeo( unsigned long arg ) {
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)arg;
++ hostdata->timeo = 1;
++ complete( &hostdata->completion );
++ return;
++}
++#endif
++
++static inline int pxa_mmc_wait_for_completion( mmc_controller_t ctrlr, u32 mask )
++{
++ int ret = -1;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++
++ if ( !xchg( &hostdata->busy, 1 ) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "there were no "
++ "interrupt awaited for\n" );
++ goto error;
++ }
++
++#if CONFIG_MMC_DEBUG_IRQ
++ hostdata->timeo = 0;
++ del_timer( &timer );
++ timer.function = wait_timeo;
++ timer.expires = jiffies + 1UL*HZ;
++ timer.data = (unsigned long)hostdata;
++ add_timer( &timer );
++#endif
++ wait_for_completion( &hostdata->completion );
++#if CONFIG_MMC_DEBUG_IRQ
++ del_timer( &timer );
++ if ( hostdata->timeo ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "irq timed out: " "mask=%x stat=%x\n", mask, MMC_STAT );
++ goto error;
++ }
++#endif
++ /* verify interrupt */
++ if ( (mask == ~0UL) || !( hostdata->mmc_i_reg & ~mask ) )
++ ret = 0;
++
++error:
++ xchg( &hostdata->busy, 0 );
++ return ret;
++}
++
++static inline int pxa_mmc_stop_bus_clock( mmc_controller_t ctrlr )
++{
++ int ret = -1;
++
++ if ( !pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_CLK_OFF ) )
++ goto out;
++
++ if ( !pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT ) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "BUFFER_IN_TRANSIT\n" );
++ goto error;
++ }
++
++ if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_CLK_IS_OFF ) )
++ goto error;
++
++ MMC_STRPCL = MMC_STRPCL_STOP_CLK;
++
++ if ( pxa_mmc_wait_for_completion( ctrlr, MMC_I_REG_CLK_IS_OFF ) )
++ goto error;
++
++ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "clock is off\n" );
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_CLK_OFF );
++out:
++ ret = 0;
++error:
++ return ret;
++}
++
++static inline int pxa_mmc_start_bus_clock( mmc_controller_t ctrlr )
++{
++ int ret = -1;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++
++ if ( (hostdata->state != PXA_MMC_FSM_CLK_OFF)
++ && (hostdata->state != PXA_MMC_FSM_END_IO) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "illegal state %s\n", PXA_MMC_STATE_LABEL( hostdata->state ) );
++ goto error;
++ }
++
++ MMC_STRPCL = MMC_STRPCL_START_CLK;
++ wmb();
++ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "clock is on\n" );
++ ret = 0;
++error:
++ return ret;
++}
++
++/*
++int pxa_mmc_complete_cmd( mmc_controller_t ctrlr, mmc_response_fmt_t response )
++
++Effects: initializes completion to wait for END_CMD_RES intr,
++ waits for intr to occur, checks controller and card status
++Requiers: controller is in CLK_OFF state
++Modifies: moves controller to the END_CMD state
++Returns:
++*/
++static mmc_error_t pxa_mmc_complete_cmd( mmc_controller_t ctrlr, mmc_response_fmt_t format, int send_abort )
++{
++ mmc_error_t ret = MMC_ERROR_GENERIC;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++ int mask, nwords;
++ u32 status;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD%d(0x%04x%04x)\n", MMC_CMD & 0x3f, MMC_ARGH, MMC_ARGL);
++
++/* FIXME: check arguments */
++
++ if ( (hostdata->state != PXA_MMC_FSM_CLK_OFF)
++ && (hostdata->state != PXA_MMC_FSM_END_IO) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "illegal state %s\n",
++ PXA_MMC_STATE_LABEL( hostdata->state ) );
++ goto error;
++ }
++
++ mask = MMC_I_MASK_END_CMD_RES;
++ if ( pxa_mmc_init_completion( ctrlr, mask ) )
++ goto error;
++
++ MMC_PRTBUF = MMC_PRTBUF_BUF_FULL;
++/* start the clock */
++ if ( pxa_mmc_start_bus_clock( ctrlr ) )
++ goto error;
++
++/* wait for END_CMD_RES intr */
++ if ( pxa_mmc_wait_for_completion( ctrlr, MMC_I_REG_END_CMD_RES ) )
++ goto error;
++
++/* check status */
++ if ( hostdata->mmc_stat & MMC_STAT_TIME_OUT_RESPONSE ) {
++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "response timeout\n");
++ ret = MMC_ERROR_TIME_OUT_RESPONSE;
++ goto error;
++
++ } else if ( hostdata->mmc_stat & MMC_STAT_READ_TIME_OUT ) {
++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "read timeout\n");
++ ret = MMC_ERROR_READ_TIME_OUT;
++ goto error;
++
++ } else if ( hostdata->mmc_stat & MMC_STAT_RES_CRC_ERROR ) {
++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "response crc err\n");
++ ret = MMC_ERROR_RES_CRC_ERROR;
++ goto error;
++
++ } else if ( hostdata->mmc_stat & MMC_STAT_CRC_READ_ERROR ) {
++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "read crc err\n");
++ ret = MMC_ERROR_CRC_READ_ERROR;
++ goto error;
++
++ } else if ( hostdata->mmc_stat & MMC_STAT_CRC_WRITE_ERROR ) {
++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "write crc err\n");
++ ret = MMC_ERROR_CRC_WRITE_ERROR;
++ goto error;
++ }
++
++ nwords = (format == MMC_NORESPONSE) ? 0 :
++ (format == MMC_R1) ? 3 :
++ (format == MMC_R2) ? 8 :
++ (format == MMC_R3) ? 3 :
++ -1;
++ ret = nwords;
++ if ( nwords > 0 ) {
++ register int i;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "nwords=%d\n", nwords );
++ for ( i = nwords - 1; i >= 0 ; i-- ) {
++ u32 res = MMC_RES;
++ int ibase = i<<1;
++
++ hostdata->mmc_res[ibase] = ((u8 *)&res)[0];
++ hostdata->mmc_res[ibase + 1] = ((u8 *)&res)[1];
++ --ret;
++ }
++#ifdef CONFIG_MMC_DEBUG
++ switch ( format ) {
++ case MMC_R1:
++ MMC_DUMP_R1( ctrlr );
++ break;
++ case MMC_R2:
++ MMC_DUMP_R2( ctrlr );
++ break;
++ case MMC_R3:
++ MMC_DUMP_R3( ctrlr );
++ break;
++ default:
++ MMC_DEBUG( MMC_DEBUG_LEVEL3,
++ "unknown response format\n" );
++ ret = MMC_ERROR_GENERIC;
++ goto error;
++ }
++#endif
++
++/* check card status for R1(b) commands */
++ if ( format == MMC_R1 ) {
++ u8 cmd;
++
++ ((u8 *)&status)[0] = hostdata->mmc_res[1];
++ ((u8 *)&status)[1] = hostdata->mmc_res[2];
++ ((u8 *)&status)[2] = hostdata->mmc_res[3];
++ ((u8 *)&status)[3] = hostdata->mmc_res[4];
++ cmd = PXA_MMC_RESPONSE( ctrlr, 5 )&0x3f;
++ MMC_DEBUG( MMC_DEBUG_LEVEL3,
++ //printk( KERN_INFO __FUNCTION__"(): "
++ "cmd=%u status: 0x%08x\n",
++ cmd, status );
++ switch ( cmd ) {
++ case 11:
++ case 18:
++ case 20:
++ case 25:
++ if ( !(status & 0x00000100) ) /* FIXME */
++ goto mmc_error;
++ default:
++ break;
++ }
++ if ( status & MMC_CARD_STATUS_OUT_OF_RANGE ) {
++ ret = MMC_ERROR_OUT_OF_RANGE;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_ADDRESS_ERROR ) {
++ ret = MMC_ERROR_ADDRESS_ERROR;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_BLOCK_LEN_ERROR ) {
++ ret = MMC_ERROR_ADDRESS_ERROR;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_ERASE_SEQ_ERROR ) {
++ ret = MMC_ERROR_ERASE_SEQ_ERROR;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_ERASE_PARAM ) {
++ ret = MMC_ERROR_ERASE_PARAM;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_WP_VIOLATION ) {
++ ret = MMC_ERROR_WP_VIOLATION;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_CARD_IS_LOCKED ) {
++ ret = MMC_ERROR_CARD_IS_LOCKED;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_LOCK_UNLOCK_FAILED ) {
++ ret = MMC_ERROR_LOCK_UNLOCK_FAILED;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_COM_CRC_ERROR ) {
++ ret = MMC_ERROR_COM_CRC_ERROR;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_ILLEGAL_COMMAND ) {
++ ret = MMC_ERROR_ILLEGAL_COMMAND;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_CARD_ECC_FAILED ) {
++ ret = MMC_ERROR_CARD_ECC_FAILED;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_CC_ERROR ) {
++ ret = MMC_ERROR_CC_ERROR;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_ERROR ) {
++ ret = MMC_ERROR_ERROR;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_UNDERRUN ) {
++ ret = MMC_ERROR_UNDERRUN;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_OVERRUN ) {
++ ret = MMC_ERROR_OVERRUN;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_CID_CSD_OVERWRITE ) {
++ ret = MMC_ERROR_CID_CSD_OVERWRITE;
++ goto mmc_error;
++ } else if ( status & MMC_CARD_STATUS_ERASE_RESET ) {
++ ret = MMC_ERROR_ERASE_RESET;
++ goto mmc_error;
++ }
++ }
++ }
++
++ if ( ret >= 0 )
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_CMD );
++ goto out;
++mmc_error:
++#if 1
++ if ( send_abort ) {
++ /* send CMD12 to abort failed transfer */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ MMC_CMD = CMD(12); /* STOP_TRANSMISSION */
++ MMC_CMDAT = MMC_CMDAT_R1;
++
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++ goto error;
++
++ ret = -EIO;
++ goto error;
++ }
++#endif
++error:
++ /* move controller to the IDLE state */
++ pxa_mmc_stop_bus_clock( ctrlr );
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE );
++out:
++ return ret;
++}
++
++/*
++int pxa_mmc_complete_io( mmc_controller_t ctrlr, mmc_dir_t cmd, mmc_dir_t dir, mmc_transfer_mode_t mode )
++
++Effects: finilizes data transfer request
++Reqires: controller is in the END_BUFFER state
++Modifies: moves controller to the IDLE state
++Returns: zero upon success or error condition code otherwise
++ */
++static mmc_error_t pxa_mmc_complete_io( mmc_controller_t ctrlr, mmc_dir_t dir, mmc_transfer_mode_t mode )
++{
++ int ret = MMC_ERROR_GENERIC;
++
++ if ( pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_END_IO ) )
++ goto error;
++
++ switch ( mode ) {
++ case MMC_TRANSFER_MODE_STREAM: /* FIXME */
++ if ( dir == MMC_WRITE ) {
++ /* 1. wait for STOP_CMD intr */
++ if ( (ret = pxa_mmc_init_completion( ctrlr,
++ MMC_I_MASK_STOP_CMD )) )
++ goto error;
++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr,
++ MMC_I_REG_STOP_CMD )) )
++ goto error;
++ }
++ /* 2. send CMD12 */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ MMC_CMD = CMD(12); /* STOP_TRANSMISSION */
++ MMC_CMDAT = MMC_CMDAT_R1;
++ if ( dir == MMC_WRITE )
++ MMC_CMDAT |= MMC_CMDAT_BUSY;
++
++ /* 3. wait for CMD12 to complete */
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "ready for CMD12\n" );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++ goto error;
++
++ /* 4. wait for DATA_TRAN_DONE intr */
++ if ( (ret = pxa_mmc_init_completion( ctrlr,
++ MMC_I_MASK_DATA_TRAN_DONE )) )
++ goto error;
++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr,
++ MMC_I_REG_DATA_TRAN_DONE )) )
++ goto error;
++
++ if ( dir == MMC_WRITE ) {
++ /* 5. wait for PRG_DONE intr */
++ if ( (ret = pxa_mmc_init_completion( ctrlr,
++ MMC_I_MASK_PRG_DONE )) )
++ goto error;
++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr,
++ MMC_I_REG_PRG_DONE )) )
++ goto error;
++ }
++ break;
++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE:
++ /* 1. wait for DATA_TRAN done intr */
++ if ( (ret = pxa_mmc_init_completion( ctrlr,
++ MMC_I_MASK_DATA_TRAN_DONE )) )
++ goto error;
++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr,
++ MMC_I_REG_DATA_TRAN_DONE )) )
++ goto error;
++
++ /* 2. send CMD12 */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ MMC_CMD = CMD(12); /* STOP_TRANSMISSION */
++ MMC_CMDAT = MMC_CMDAT_R1;
++ if ( dir == MMC_WRITE )
++ MMC_CMDAT |= MMC_CMDAT_BUSY;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD12\n" );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++ goto error;
++
++ if ( dir == MMC_WRITE ) {
++ /* 3. wait for PRG_DONE intr */
++ if ( (ret = pxa_mmc_init_completion( ctrlr,
++ MMC_I_MASK_PRG_DONE )) )
++ goto error;
++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr,
++ MMC_I_REG_PRG_DONE )) )
++ goto error;
++ }
++ break;
++ case MMC_TRANSFER_MODE_BLOCK_SINGLE:
++ /* 1. wait for DATA_TRAN_DONE intr */
++ if ( (ret = pxa_mmc_init_completion( ctrlr,
++ MMC_I_MASK_DATA_TRAN_DONE )) )
++ goto error;
++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr,
++ MMC_I_REG_DATA_TRAN_DONE )) )
++ goto error;
++
++ if ( dir == MMC_WRITE ) {
++ /* 2. wait for PRG_DONE intr */
++ if ( (ret = pxa_mmc_init_completion( ctrlr,
++ MMC_I_MASK_PRG_DONE )) )
++ goto error;
++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr,
++ MMC_I_REG_PRG_DONE )) )
++ goto error;
++ }
++ break;
++ default:
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown transfer mode\n" );
++ goto error;
++ }
++/* move the controller to the IDLE state */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE );
++
++ ret = 0;
++error:
++ return ret;
++}
++
++static inline int pxa_mmc_update_acq( mmc_controller_t ctrlr )
++{
++ int ret = -EINVAL;
++ pxa_mmc_hostdata_t hostdata = NULL;
++ mmc_card_t card = NULL;
++ mmc_card_stack_rec_t fake;
++ mmc_card_stack_t stack = &fake;
++ u16 argl = 0U, argh = 0U;
++ int ncards = 0;
++
++ if ( !ctrlr )
++ goto error;
++
++ hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++
++ __mmc_card_stack_init( stack );
++
++ /* max open-drain mode frequency is 400kHZ */
++ MMC_CLKRT = MMC_CLKRT_0_3125MHZ;
++ MMC_RESTO = MMC_RES_TO_MAX; /* set response timeout */
++
++ /* discover and add cards to the stack */
++ /* I. bus operation condition setup */
++ /* 1) send CMD1 */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto err_free;
++
++ argl = 0x0000;
++ argh = 0x0004;
++
++ MMC_CMD = CMD(1);
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++
++ MMC_CMDAT = MMC_CMDAT_BUSY|MMC_CMDAT_R3;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD1(0x%04x%04x)\n", argh, argl );
++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R3, FALSE );
++ if ( !ret ) {
++ argh = (PXA_MMC_RESPONSE( ctrlr, 4 ) << 8)
++ | PXA_MMC_RESPONSE( ctrlr, 3 );
++ argl = (PXA_MMC_RESPONSE( ctrlr, 2 ) << 8)
++ | PXA_MMC_RESPONSE( ctrlr, 1 );
++
++ } else if ( ret != MMC_ERROR_TIME_OUT_RESPONSE )
++ goto err_free;
++
++ if ( !argh && !argl ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL3,
++ "assuming full voltage range support\n" );
++ argh = 0x00ff;
++ argl = 0xff00;
++ }
++
++ /* 2) continuously send CMD1 'till there're busy cards */
++ for(;;) {
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto err_free;
++
++ MMC_CMD = CMD(1);
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++
++ MMC_CMDAT = MMC_CMDAT_BUSY|MMC_CMDAT_R3;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD1(0x%04x%04x)\n", argh, argl );
++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R3, FALSE );
++ if ( ret == MMC_ERROR_TIME_OUT_RESPONSE )
++ break;
++
++ else if ( !ret ) {
++ /* busy state reported by LOW signal level
++ * (MMC v3.2, p.58)
++ *
++ * Thanks to Alexander Samoutin :)
++ */
++ if ( !(PXA_MMC_RESPONSE( ctrlr, 4 ) & 0x80) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "busy state reported\n");
++ udelay( 20 );
++ continue;
++ } else
++ break;
++ } else
++ goto err_free;
++ }
++
++/* II. card identification: the cards in Ready state
++ * are the only expected to respond
++ */
++ for (;;) {
++ argh = 0U;
++ argl = 0U;
++
++ /* 1) send CMD2 */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto err_free;
++
++ MMC_CMD = CMD(2);
++ MMC_ARGH = 0x0003;
++ MMC_ARGL = 0xf300;
++ MMC_CMDAT = MMC_CMDAT_R2;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD2(0x%04x%04x)\n", argh, argl );
++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R2, FALSE );
++ if ( ret == MMC_ERROR_TIME_OUT_RESPONSE )
++ break;
++
++ else if ( ret ) /* bus error */
++ goto err_free;
++
++ /* TODO: store CID for the card */
++
++ /* 2) assign RCA */
++ if ( !++ctrlr->rca_next ) /* overflow */
++ ++ctrlr->rca_next;
++ argh = ctrlr->rca_next;
++
++ /* 3) send it to the card last responded (CMD3) */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto err_free;
++
++ MMC_CMD = CMD(3);
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_CMDAT = MMC_CMDAT_R1;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD3(0x%04x%04x)\n", argh, argl );
++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE );
++ if ( ret ) /* CMD3 failed */
++ goto err_free;
++
++ card = __mmc_card_alloc( sizeof( pxa_mmc_card_data_rec_t ) );
++ if ( !card ) {
++ MMC_ERROR( "out of memory\n" );
++ goto err_free;
++ }
++
++ card->info.rca = argh;
++ card->slot = ctrlr->slot_next++; /* FIXME: minor encoding */
++ card->ctrlr = ctrlr;
++
++ if ( !__mmc_card_stack_add( stack, card ) )
++ goto err_free;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "added card: "
++ "slot %d, RCA=0x%04x\n", card->slot, argh );
++ ++ncards;
++ }
++
++ if ( ncards ) {
++/* III. read CSD registers of all cards; DSR support also reported there */
++ for ( card = stack->first; card; card = card->next ) {
++ pxa_mmc_card_data_t card_data =
++ (pxa_mmc_card_data_t)card->card_data;
++
++ /* 1) send CMD9 */
++ argh = card->info.rca;
++ argl = 0U;
++
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto err_free;
++
++ MMC_CMD = CMD(9);
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_CMDAT = MMC_CMDAT_R2;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3,
++ "CMD9(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R2, FALSE )) )
++ goto err_free;
++
++ memcpy( &card->info.csd, hostdata->mmc_res, 15 );
++ MMC_DUMP_CSD( card );
++
++ card->info.read_bl_len = (1<<card->info.csd.read_bl_len);
++ card->info.write_bl_len = (1<<card->info.csd.write_bl_len);
++ card->info.capacity = (card->info.csd.c_size + 1)
++ * (1<<(card->info.csd.c_size_mult + 2))
++ * card->info.read_bl_len;
++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "card capacity=%dMb\n",
++ card->info.capacity>>20 );
++ card->info.tran_speed = 20*1024; /* FIXME */
++ card->info.transfer_mode = MMC_TRANSFER_MODE_BLOCK_SINGLE;
++ /* 2) set bus operation freq */
++ card_data->clkrt = pxa_mmc_clkrt( card->info.tran_speed );
++ /* 3) register card with MMC core */
++ mmc_register( MMC_REG_TYPE_CARD, card, 0 );
++ }
++/* IV. set DSR registers of the cards */
++#if 0 /* TODO */
++ if ( card->info.csd.dsr_imp ) {
++ set_dsr = TRUE;
++ /* calculate DSR */
++ }
++#endif
++ }
++#if 0 /* TODO */
++ if ( set_dsr ) {
++ /* send CMD4 */
++ }
++#endif
++/* merge list of the newly inserted cards into controller card stack */
++ if ( !ctrlr->stack.ncards ) {
++ ctrlr->stack.first = stack->first;
++ ctrlr->stack.last = stack->last;
++ } else
++ ctrlr->stack.last->next = stack->first;
++
++ ctrlr->stack.ncards += stack->ncards;
++
++ ret = 0;
++ goto out;
++err_free:
++ __mmc_card_stack_free( stack );
++error:
++out:
++ return ret;
++}
++
++/* MMC protocol macros: v3.4, p.120 */
++static int pxa_mmc_init_card_stack( mmc_controller_t ctrlr )
++{
++ int ret = -EIO;
++ u16 argl = 0U, argh = 0U;
++
++ if ( !ctrlr || ctrlr->stack.ncards ) {
++ ret = -EINVAL;
++ goto error;
++ }
++
++ /* initialize stack */
++ /* 1) send CMD0 */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ /* max open-drain mode frequency is 400kHZ */
++ MMC_CLKRT = MMC_CLKRT_0_3125MHZ;
++ MMC_RESTO = MMC_RES_TO_MAX; /* set response timeout */
++ MMC_SPI = MMC_SPI_DISABLE;
++
++ MMC_CMD = CMD(0); /* CMD0 with zero argument */
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_CMDAT = MMC_CMDAT_INIT;
++
++ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD0(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_NORESPONSE, FALSE )) )
++ goto error;
++
++ /* update card stack */
++ if ( (ret = pxa_mmc_update_acq( ctrlr )) )
++ goto err_free;
++
++ /* move the controller to the IDLE state */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto err_free;
++
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE );
++
++ ret = 0;
++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "ncards=%d\n", ctrlr->stack.ncards );
++ goto out;
++
++err_free:
++ __mmc_card_stack_free( &ctrlr->stack );
++error:
++out:
++ return ret;
++}
++
++static int pxa_mmc_check_card_stack( mmc_controller_t ctrlr )
++{
++ int ret = -1;
++ mmc_card_t card;
++
++ if ( !ctrlr )
++ goto error;
++
++ if ( ctrlr->stack.ncards > 0 ) {
++/* for each card in the stack: */
++ for( card = ctrlr->stack.first; card; card = card->next ) {
++ u16 argh = card->info.rca;
++ u16 argl = 0UL;
++
++/* 1) send CMD9( card->rca ) */
++ if ( pxa_mmc_stop_bus_clock( ctrlr ) )
++ goto error;
++
++ /* SanDisk's cards do not respond to CMD9 */
++ MMC_CMD = CMD(13);
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_CMDAT = MMC_CMDAT_R1;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD13(0x%04x%04x)\n",
++ argh, argl );
++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE );
++/* 2) if card responded, it is still there */
++ if ( ret )
++ card->state = MMC_CARD_STATE_UNPLUGGED;
++ }
++ }
++ ret = 0;
++error:
++ return ret;
++}
++
++/* This procedure links the bus master with a single card
++ * 1) cross checks with the internal stack management data if a card still
++ * exists in the slot
++ * 2) send CMD7( card->public.rca )
++ * 3) setup data path and controller options
++ */
++static int pxa_mmc_setup_card( mmc_controller_t ctrlr, mmc_card_t card )
++{
++ int ret = -ENODEV;
++ pxa_mmc_hostdata_t hostdata;
++ pxa_mmc_card_data_t card_data;
++ u16 argh = 0U;
++#ifdef CONFIG_MMC_DEBUG
++ u16 argl = 0U;
++#endif
++
++ if ( !ctrlr || !card ) {
++ ret = -EINVAL;
++ goto error;
++ }
++
++ if ( card->ctrlr != ctrlr ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "card is on another bus\n" );
++ goto error;
++ }
++
++ hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++ card_data = (pxa_mmc_card_data_t)card->card_data;
++
++ argh = card->info.rca;
++
++/* select requested card */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ MMC_CMD = CMD(7);
++ MMC_ARGH = argh;
++ MMC_CMDAT = MMC_CMDAT_R1;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD7(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++ goto error;
++
++/* set controller options */
++#ifndef CONFIG_MMC_DEBUG
++ MMC_CLKRT = card_data->clkrt;
++#endif
++/* move the controller to the IDLE state */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE );
++
++ ret = 0;
++error:
++ return ret;
++}
++
++static inline int pxa_mmc_iobuf_init( mmc_controller_t ctrlr, ssize_t cnt )
++{
++#ifdef PIO
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++#endif
++#ifndef PIO
++/* TODO */
++#else
++ hostdata->iobuf.buf.pos = hostdata->iobuf.iodata;
++ hostdata->iobuf.buf.cnt = cnt;
++#endif
++ return 0;
++}
++/* TODO: ssize_t pxa_mmc_read_buffer( mmc_controller_t ctrlr, ssize_t cnt )
++effects: reads at most cnt bytes from the card to the controller I/O buffer;
++ takes care of partial data transfers
++requieres:
++modifies: ctrlr->iobuf
++returns: number of bytes actually transferred or negative error code if there were any errors
++ */
++ssize_t pxa_mmc_read_buffer( mmc_controller_t ctrlr, ssize_t cnt )
++{
++ ssize_t ret = -EIO;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++#ifndef PIO
++ register int ndesc;
++ int chan = hostdata->iobuf.buf.chan;
++ pxa_dma_desc *desc;
++#endif
++
++ if ( (hostdata->state != PXA_MMC_FSM_END_CMD) && (hostdata->state != PXA_MMC_FSM_END_BUFFER) ) {
++ goto error;
++ }
++
++ if ( cnt > hostdata->iobuf.bufsz )
++ cnt = hostdata->iobuf.bufsz;
++
++ if ( (ret = pxa_mmc_iobuf_init( ctrlr, cnt )) )
++ goto error;
++
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT );
++#ifndef PIO
++ if ( pxa_mmc_init_completion( ctrlr, ~MMC_I_MASK_ALL ) ) /* FIXME */
++ goto error;
++
++ if ( (desc = hostdata->iobuf.buf.last_read_desc) ) {
++ desc->ddadr &= ~DDADR_STOP;
++ desc->dcmd &= ~(DCMD_ENDIRQEN|DCMD_LENGTH);
++ desc->dcmd |= (1<<5);
++ }
++/* 1) setup descriptors for DMA transfer from the device */
++ ndesc = (cnt>>5) - 1; /* FIXME: partial read */
++ desc = &hostdata->iobuf.buf.read_desc[ndesc];
++ hostdata->iobuf.buf.last_read_desc = desc;
++ /* TODO: partial read */
++ desc->ddadr |= DDADR_STOP;
++ desc->dcmd |= DCMD_ENDIRQEN;
++/* 2) start DMA channel */
++ DDADR( chan ) = hostdata->iobuf.buf.read_desc_phys_addr;
++ DCSR( chan ) |= DCSR_RUN;
++#else
++ if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_RXFIFO_RD_REQ ) )
++ goto error;
++#endif
++
++ if ( pxa_mmc_wait_for_completion( ctrlr, ~0UL ) )
++ goto error;
++
++ if ( pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_END_BUFFER ) )
++ goto error;
++
++ if ( !(hostdata->mmc_stat & MMC_STAT_ERRORS) ) /* FIXME */
++ ret = cnt;
++error:
++ return ret;
++}
++
++ssize_t pxa_mmc_write_buffer( mmc_controller_t ctrlr, ssize_t cnt )
++{
++ ssize_t ret = -EIO;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++#ifndef PIO
++ register int ndesc;
++ int chan = hostdata->iobuf.buf.chan;
++ pxa_dma_desc *desc;
++#endif
++
++ if ( (hostdata->state != PXA_MMC_FSM_END_CMD)
++ && (hostdata->state != PXA_MMC_FSM_END_BUFFER) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unexpected state (%s)\n",
++ PXA_MMC_STATE_LABEL( hostdata->state ) );
++ goto error;
++ }
++
++ if ( cnt > hostdata->iobuf.bufsz )
++ cnt = hostdata->iobuf.bufsz;
++
++ if ( (ret = pxa_mmc_iobuf_init( ctrlr, cnt )) )
++ goto error;
++
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT );
++#ifndef PIO
++ if ( pxa_mmc_init_completion( ctrlr, ~MMC_I_MASK_ALL ) ) /* FIXME */
++ goto error;
++ if ( (desc = hostdata->iobuf.buf.last_write_desc) ) {
++ desc->ddadr &= ~DDADR_STOP;
++ desc->dcmd &= ~(DCMD_ENDIRQEN|DCMD_LENGTH);
++ desc->dcmd |= (1<<5);
++ }
++/* 1) setup descriptors for DMA transfer to the device */
++ ndesc = (cnt>>5) - 1; /* FIXME: partial write */
++ desc = &hostdata->iobuf.buf.write_desc[ndesc];
++ /* TODO: partial write */
++ hostdata->iobuf.buf.last_write_desc = desc;
++ desc->ddadr |= DDADR_STOP;
++ desc->dcmd |= DCMD_ENDIRQEN;
++/* 2) start DMA channel */
++ DDADR( chan ) = hostdata->iobuf.buf.write_desc_phys_addr;
++ DCSR( chan ) |= DCSR_RUN;
++#else
++ if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_TXFIFO_WR_REQ ) )
++ goto error;
++#endif
++ if ( pxa_mmc_wait_for_completion( ctrlr, ~0UL ) )
++ goto error;
++
++ if ( pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_END_BUFFER ) )
++ goto error;
++
++ if ( !(hostdata->mmc_stat & MMC_STAT_ERRORS) ) /* FIXME */
++ ret = cnt;
++error:
++ return ret;
++}
++
++/* TODO: ssize_t pxa_mmc_copy_from_buffer( ctrlr, mmc_buftype_t to, char *buf, ssize_t cnt )
++effects: copies at most cnt bytes from the controller I/O buffer to the user or kernel buffer
++ pointed by buf
++requiers:
++modifies:
++returns: number of bytes actually transferred or negative error code if there were any errors
++ */
++ssize_t pxa_mmc_copy_from_buffer( mmc_controller_t ctrlr, mmc_buftype_t to, char *buf, ssize_t cnt )
++{
++ ssize_t ret = -EIO;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++
++#ifndef PIO
++/* TODO: check that DMA channel is not running */
++#endif
++ switch ( to ) {
++ case MMC_USER:
++ if ( copy_to_user( buf, hostdata->iobuf.iodata, cnt ) ) {
++ ret = -EFAULT;
++ goto error;
++ }
++ break;
++ case MMC_KERNEL:
++ memcpy( buf, hostdata->iobuf.iodata, cnt );
++ break;
++ default:
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown buffer type\n" );
++ goto error;
++ }
++ ret = cnt;
++error:
++ return ret;
++}
++
++ssize_t pxa_mmc_copy_to_buffer( mmc_controller_t ctrlr, mmc_buftype_t to, char *buf, ssize_t cnt )
++{
++ ssize_t ret = -EIO;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++#ifndef PIO
++/* check that DMA channel is not running */
++#endif
++ switch ( to ) {
++ case MMC_USER:
++ if ( copy_from_user( hostdata->iobuf.iodata, buf, cnt ) ) {
++ ret = -EFAULT;
++ goto error;
++ }
++ break;
++ case MMC_KERNEL:
++ memcpy( hostdata->iobuf.iodata, buf, cnt );
++ break;
++ default:
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown buffer type\n" );
++ goto error;
++ }
++ ret = cnt;
++error:
++ return ret;
++}
++
++/* This procedure sequentally passes the data from the user buffer to the card */
++static int pxa_mmc_stream_read( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer )
++{
++ int ret = -EIO;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++ u16 argh = 0UL, argl = 0UL;
++ ssize_t size = 0;
++
++ while ( transfer->cnt > 0 ) {
++ size = (transfer->cnt < hostdata->iobuf.blksz) ?
++ transfer->cnt : hostdata->iobuf.blksz;
++ /* 1. send CMD11 */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ argh = transfer->addr >> 16;
++ argl = transfer->addr;
++ /* 2. setup controller registers to start stream data transfer */
++ MMC_CMD = CMD(11); /* READ_DAT_UNTIL_STOP */
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_NOB = 0xffff;
++ MMC_BLKLEN = size;
++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_STREAM|MMC_CMDAT_DATA_EN;
++#ifndef PIO
++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN;
++#endif
++ /* 3. wait for cmd to complete */
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD11(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) )
++ goto error;
++
++ /* 4. transfer the data to the caller supplied buffer */
++ if ( (ret = pxa_mmc_read_buffer( ctrlr, size )) < 0 )
++ goto error;
++
++ if ( (ret = pxa_mmc_copy_from_buffer( ctrlr, transfer->type, transfer->buf, ret )) < 0 )
++ goto error;
++
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );
++
++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )
++ goto error;
++
++ transfer->buf += ret;
++ transfer->addr += ret;
++ transfer->cnt -= ret;
++ }
++ ret = 0;
++error:
++ return ret;
++}
++
++/* This procedure reads a data block from a card at a given kernel address */
++static int pxa_mmc_read_block( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer )
++{
++ int ret = -ENODEV;
++ u16 argh = 0UL, argl = 0UL;
++
++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default
++ * for the current card */
++ if ( transfer->blksz != ctrlr->stack.selected->info.read_bl_len ) {
++ argh = transfer->blksz >> 16;
++ argl = transfer->blksz;
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ MMC_CMD = CMD(16); /* SET_BLOCK_LEN */
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_CMDAT = MMC_CMDAT_R1;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3,
++ "CMD16(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++ goto error;
++ }
++
++/* CMD17 (READ_SINGLE_BLOCK) */
++ argh = transfer->addr >> 16;
++ argl = transfer->addr;
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ MMC_CMD = CMD(17); /* READ_SINGLE_BLOCK */
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN;
++ MMC_NOB = 1;
++ MMC_BLKLEN = transfer->blksz;
++#ifndef PIO
++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN;
++#endif
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD17(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++ goto error;
++
++/* transfer the data to the caller supplied buffer */
++ if ( (ret = pxa_mmc_read_buffer( ctrlr, transfer->blksz )) < 0 )
++ goto error;
++
++ if ( (ret = pxa_mmc_copy_from_buffer( ctrlr, transfer->type, transfer->buf, ret )) < 0 )
++ goto error;
++
++ transfer->buf += ret;
++ transfer->cnt -= ret;
++ transfer->nob -= 1;
++
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );
++
++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )
++ goto error;
++
++ ret = 0;
++error:
++ return ret;
++}
++
++/* This procedure sequentally reads data blocks from
++ * a card to the user buffer. Controller options and block size
++ * are already set by setup_card(). Data alignment and partial
++ * data accessibility assumed to be checked by mmc_core */
++static int pxa_mmc_read_mblock( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer )
++{
++ int ret = -EIO;
++ u16 argh = 0UL, argl = 0UL;
++
++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default
++ * for the current card */
++ if ( transfer->blksz != ctrlr->stack.selected->info.read_bl_len ) {
++ argh = transfer->blksz >> 16;
++ argl = transfer->blksz;
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ MMC_CMD = CMD(16); /* SET_BLOCK_LEN */
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_CMDAT = MMC_CMDAT_R1;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++ goto error;
++ }
++
++ argh = transfer->addr >> 16;
++ argl = transfer->addr;
++/* 1. stop bus clock */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++/* 2. setup controller registers to start multiple block transfer */
++ MMC_CMD = CMD(18); /* READ_MULTIPLE_BLOCK */
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_NOB = transfer->nob;
++ MMC_BLKLEN = transfer->blksz;
++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN;
++#ifndef PIO
++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN;
++#endif
++
++/* 3. start clock */
++ if ( (ret = pxa_mmc_start_bus_clock( ctrlr )) )
++ goto error;
++
++/* 4. wait for cmd to complete */
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD18(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) )
++ goto error;
++
++/* 6. transfer the data to the caller supplied buffer */
++ while ( transfer->cnt > 0 ) {
++ if ( (ret = pxa_mmc_read_buffer( ctrlr, transfer->cnt )) < 0 )
++ goto error;
++
++ if ( (ret = pxa_mmc_copy_from_buffer( ctrlr, transfer->type, transfer->buf, ret )) < 0 )
++ goto error;
++
++ transfer->buf += ret;
++ transfer->cnt -= ret;
++ }
++
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );
++
++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )
++ goto error;
++
++ ret = 0;
++error:
++ return ret;
++}
++
++/* Sequentally writes the data from a user buffer to the card */
++static int pxa_mmc_stream_write( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer )
++{
++ int ret = -EIO;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++ u16 argh = 0UL, argl = 0UL;
++ ssize_t size = 0;
++
++ __ENTER( "transfer: cmd=%d mode=%d type=%d blksz=%d "
++ "nob=%d buf=%p cnt=%d addr=%Lx", transfer->cmd,
++ transfer->mode, transfer->type, transfer->blksz,
++ transfer->nob, transfer->buf, transfer->cnt, transfer->addr );
++
++ argh = transfer->addr >> 16;
++ argl = transfer->addr;
++/* 1. stop bus clock */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++/* 2. setup controller registers to start stream data transfer */
++ MMC_CMD = CMD(20); /* WRITE_DAT_UNTIL_STOP */
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_NOB = 0xffff;
++ MMC_BLKLEN = hostdata->iobuf.blksz;
++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_STREAM|MMC_CMDAT_DATA_EN;
++#ifndef PIO
++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN;
++#endif
++
++/* 3. wait for cmd to complete */
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD20(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) )
++ goto error;
++
++/* 4. transfer the data to the caller supplied buffer */
++ while ( transfer->cnt > 0 ) {
++ size = (transfer->cnt < hostdata->iobuf.blksz) ?
++ transfer->cnt : hostdata->iobuf.blksz;
++ if ( (ret = pxa_mmc_copy_to_buffer( ctrlr,
++ transfer->type, transfer->buf, size )) < 0 )
++ goto error;
++
++ if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 )
++ goto error;
++
++ transfer->buf += ret;
++ transfer->cnt -= ret;
++ }
++
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );
++
++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )
++ goto error;
++
++ ret = 0;
++error:
++ return ret;
++}
++
++/* This procedure writes a data block to a card at a given address */
++static int pxa_mmc_write_block( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer )
++{
++ int ret = -ENODEV;
++ u16 argh = 0UL, argl = 0UL;
++
++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default
++ * for the current card */
++ if ( transfer->blksz != ctrlr->stack.selected->info.read_bl_len ) {
++ argh = transfer->blksz >> 16;
++ argl = transfer->blksz;
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ MMC_CMD = CMD(16); /* SET_BLOCK_LEN */
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_CMDAT = MMC_CMDAT_R1;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++ goto error;
++ }
++
++/* CMD17 (READ_SINGLE_BLOCK) */
++ argh = transfer->addr >> 16;
++ argl = transfer->addr;
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ MMC_CMD = CMD(24); /* WRITE_BLOCK */
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN;
++#ifndef PIO
++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN;
++#endif
++ MMC_NOB = 1;
++ MMC_BLKLEN = transfer->blksz;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD24(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++ goto error;
++
++/* transfer the data to the caller supplied buffer */
++ if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, transfer->type, transfer->buf, transfer->cnt )) < 0 )
++ goto error;
++
++ if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 )
++ goto error;
++
++ transfer->buf += ret;
++ transfer->cnt -= ret;
++ transfer->nob -= 1;
++
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );
++
++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )
++ goto error;
++
++ ret = 0;
++error:
++ return ret;
++}
++
++/* This procedure sequentally writes data blocks to a card at a given address */
++static ssize_t pxa_mmc_write_mblock( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer )
++{
++ int ret = -EIO;
++ u16 argh = 0UL, argl = 0UL;
++
++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default
++ * for the current card */
++ if ( transfer->blksz != ctrlr->stack.selected->info.write_bl_len ) {
++ argh = transfer->blksz >> 16;
++ argl = transfer->blksz;
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ MMC_CMD = CMD(16); /* SET_BLOCK_LEN */
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_CMDAT = MMC_CMDAT_R1;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++ goto error;
++ }
++
++ argh = transfer->addr >> 16;
++ argl = transfer->addr;
++/* 1. stop bus clock */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++/* 2. setup controller registers to start multiple block transfer */
++ MMC_CMD = CMD(25); /* WRITE_MULTIPLE_BLOCK */
++ MMC_ARGH = argh;
++ MMC_ARGL = argl;
++ MMC_NOB = transfer->nob;
++ MMC_BLKLEN = transfer->blksz;
++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN;
++#ifndef PIO
++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN;
++#endif
++
++/* 3. start clock */
++ if ( (ret = pxa_mmc_start_bus_clock( ctrlr )) )
++ goto error;
++
++/* 4. wait for cmd to complete */
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD25(0x%04x%04x)\n", argh, argl );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) )
++ goto error;
++
++/* 6. transfer the data to the caller supplied buffer */
++ while ( transfer->cnt > 0 ) {
++ if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, transfer->type,
++ transfer->buf, transfer->cnt )) < 0 )
++ goto error;
++
++ if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 )
++ goto error;
++
++ transfer->buf += ret;
++ transfer->cnt -= ret;
++ }
++
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );
++
++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )
++ goto error;
++
++ ret = 0;
++error:
++ return ret;
++}
++
++static void pxa_mmc_irq( int irq, void *dev_id, struct pt_regs *regs )
++{
++ mmc_controller_t ctrlr = (mmc_controller_t)dev_id;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++#ifdef PIO
++ register int i, cnt;
++ register char *buf;
++#endif
++
++ hostdata->mmc_i_reg = MMC_I_REG;
++ hostdata->mmc_stat = MMC_STAT;
++ hostdata->mmc_cmdat = MMC_CMDAT;
++#if 0
++ if (hostdata->mmc_i_reg != 0x0010) {
++ printk("IREG %08x", hostdata->mmc_i_reg);
++ if (hostdata->mmc_i_reg & 0x0001) printk(" DATA_TRAN_DONE");
++ if (hostdata->mmc_i_reg & 0x0002) printk(" PRG_DONE");
++ if (hostdata->mmc_i_reg & 0x0004) printk(" END_CMD");
++ if (hostdata->mmc_i_reg & 0x0008) printk(" STOP_CMD");
++ if (hostdata->mmc_i_reg & 0x0010) printk(" CLK_OFF");
++ if (hostdata->mmc_i_reg & 0x0020) printk(" RX_FIFO");
++ if (hostdata->mmc_i_reg & 0x0040) printk(" TX_FIFO");
++ printk("\nSTAT %08x", hostdata->mmc_stat);
++ if (hostdata->mmc_stat & 0x0001) printk(" READ_TO");
++ if (hostdata->mmc_stat & 0x0002) printk(" RESP_TO");
++ if (hostdata->mmc_stat & 0x0004) printk(" WR_CRC");
++ if (hostdata->mmc_stat & 0x0008) printk(" READ_CRC");
++ if (hostdata->mmc_stat & 0x0010) printk(" SPI_RD_TKN");
++ if (hostdata->mmc_stat & 0x0020) printk(" RESP_CRC");
++ if (hostdata->mmc_stat & 0x0040) printk(" TX_FIFO");
++ if (hostdata->mmc_stat & 0x0080) printk(" RX_FIFO");
++ if (hostdata->mmc_stat & 0x0100) printk(" CLK");
++ if (hostdata->mmc_stat & 0x0800) printk(" DATA_TRAN_DONE");
++ if (hostdata->mmc_stat & 0x1000) printk(" PRG_DONE");
++ if (hostdata->mmc_stat & 0x2000) printk(" END_CMD");
++ printk("\n");
++ }
++#endif
++
++#if CONFIG_MMC_DEBUG_IRQ
++ if ( --hostdata->irqcnt <= 0 ) {
++ printk( KERN_INFO __FUNCTION__"(): irqcnt exceeded\n" );
++ goto complete;
++ }
++#endif
++ switch ( hostdata->state ) {
++ case PXA_MMC_FSM_IDLE:
++ case PXA_MMC_FSM_CLK_OFF:
++ case PXA_MMC_FSM_END_IO:
++ case PXA_MMC_FSM_END_BUFFER:
++ case PXA_MMC_FSM_END_CMD:
++ goto complete;
++#ifdef PIO
++ case PXA_MMC_FSM_BUFFER_IN_TRANSIT:
++ if ( hostdata->mmc_stat & MMC_STAT_ERRORS )
++ goto complete;
++
++ buf = hostdata->iobuf.buf.pos;
++ cnt = (hostdata->iobuf.buf.cnt < 32) ?
++ hostdata->iobuf.buf.cnt : 32;
++ if ( hostdata->mmc_cmdat & MMC_CMDAT_WRITE ) {
++ if ( !(hostdata->mmc_stat & MMC_STAT_XMIT_FIFO_EMPTY) )
++ break;
++ for ( i = 0; i < cnt; i++ )
++ MMC_TXFIFO = *buf++;
++ if ( cnt < 32 )
++ MMC_PRTBUF = MMC_PRTBUF_BUF_PART_FULL;
++ } else { /* i.e. MMC_CMDAT_READ */
++ if( !(hostdata->mmc_stat & MMC_STAT_RECV_FIFO_FULL) )
++ break;
++ for( i = 0; i < cnt; i++ )
++ *buf++ = MMC_RXFIFO;
++ }
++
++ hostdata->iobuf.buf.pos = buf;
++ hostdata->iobuf.buf.cnt -= i;
++ if ( hostdata->iobuf.buf.cnt <= 0 ) {
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_BUFFER );
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "buffer transferred\n" );
++ goto complete;
++ }
++ break;
++#endif /* PIO */
++ default:
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unexpected state %d\n",
++ hostdata->state );
++ goto complete;
++ }
++ return;
++complete:
++ MMC_I_MASK = MMC_I_MASK_ALL;
++ complete( &hostdata->completion );
++ return;
++}
++
++#ifndef PIO
++static void pxa_mmc_dma_irq( int irq, void *dev_id, struct pt_regs *regs )
++{
++ mmc_controller_t ctrlr = (mmc_controller_t)dev_id;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++ u32 dcsr;
++ u32 ddadr;
++ int chan = hostdata->iobuf.buf.chan;
++
++ ddadr = DDADR( chan );
++ dcsr = DCSR( chan );
++ DCSR( chan ) = dcsr & ~DCSR_STOPIRQEN;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3,
++ "MMC DMA interrupt: chan=%d ddadr=0x%08x "
++ "dcmd=0x%08x dcsr=0x%08x\n",
++ chan, ddadr, DCMD( chan ), dcsr );
++/* bus error */
++ if ( dcsr & DCSR_BUSERR ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "bus error on DMA channel %d\n",
++ chan );
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_ERROR );
++ goto complete;
++ }
++/* data transfer completed */
++ if ( dcsr & DCSR_ENDINTR ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "buffer transferred\n" );
++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_BUFFER );
++ goto complete;
++ }
++ return;
++complete:
++ complete( &hostdata->completion );
++ return;
++}
++#endif
++
++
++static int pxa_mmc_init( mmc_controller_t ctrlr )
++{
++ int ret = -ENODEV;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++#ifndef PIO
++ register int i;
++ register pxa_dma_desc *desc;
++#endif
++
++/* hardware initialization */
++/* I. prepare to transfer data */
++/* 1. allocate buffer */
++#ifndef PIO
++ hostdata->iobuf.buf.read_desc = consistent_alloc( GFP_KERNEL,
++ (PXA_MMC_IODATA_SIZE>>5)
++ * sizeof( pxa_dma_desc ),
++ &hostdata->iobuf.buf.read_desc_phys_addr, 0 );
++ if ( !hostdata->iobuf.buf.read_desc ) {
++ ret = -ENOMEM;
++ goto error;
++ }
++ hostdata->iobuf.buf.write_desc = consistent_alloc( GFP_KERNEL,
++ (PXA_MMC_IODATA_SIZE>>5)
++ * sizeof( pxa_dma_desc ),
++ &hostdata->iobuf.buf.write_desc_phys_addr, 0 );
++ if ( !hostdata->iobuf.buf.write_desc ) {
++ ret = -ENOMEM;
++ goto error;
++ }
++ hostdata->iobuf.iodata = consistent_alloc( GFP_ATOMIC,
++ PXA_MMC_IODATA_SIZE,
++ &hostdata->iobuf.buf.phys_addr, 0 );
++#else
++ hostdata->iobuf.iodata = kmalloc( PXA_MMC_IODATA_SIZE, GFP_ATOMIC );
++#endif
++ if ( !hostdata->iobuf.iodata ) {
++ ret = -ENOMEM;
++ goto error;
++ }
++/* 2. initialize iobuf */
++ hostdata->iobuf.blksz = PXA_MMC_BLKSZ_MAX;
++ hostdata->iobuf.bufsz = PXA_MMC_IODATA_SIZE;
++ hostdata->iobuf.nob = PXA_MMC_BLOCKS_PER_BUFFER;
++#ifndef PIO
++ /* request DMA channel */
++ if ( (hostdata->iobuf.buf.chan = pxa_request_dma( "MMC", DMA_PRIO_LOW,
++ pxa_mmc_dma_irq, ctrlr )) < 0 ) {
++ MMC_ERROR( "failed to request DMA channel\n" );
++ goto error;
++ }
++
++ DRCMRRXMMC = hostdata->iobuf.buf.chan | DRCMR_MAPVLD;
++ DRCMRTXMMC = hostdata->iobuf.buf.chan | DRCMR_MAPVLD;
++
++ for ( i = 0; i < ((PXA_MMC_IODATA_SIZE>>5) - 1); i++ ) {
++ desc = &hostdata->iobuf.buf.read_desc[i];
++ desc->ddadr = hostdata->iobuf.buf.read_desc_phys_addr
++ + ((i + 1) * sizeof( pxa_dma_desc ));
++ desc->dsadr = MMC_RXFIFO_PHYS_ADDR;
++ desc->dtadr = hostdata->iobuf.buf.phys_addr + (i<<5);
++ desc->dcmd = DCMD_FLOWSRC|DCMD_INCTRGADDR
++ |DCMD_WIDTH1|DCMD_BURST32|(1<<5);
++
++ desc = &hostdata->iobuf.buf.write_desc[i];
++ desc->ddadr = hostdata->iobuf.buf.write_desc_phys_addr
++ + ((i + 1) * sizeof( pxa_dma_desc ));
++ desc->dsadr = hostdata->iobuf.buf.phys_addr + (i<<5);
++ desc->dtadr = MMC_TXFIFO_PHYS_ADDR;
++ desc->dcmd = DCMD_FLOWTRG|DCMD_INCSRCADDR
++ |DCMD_WIDTH1|DCMD_BURST32|(1<<5);
++ }
++ desc = &hostdata->iobuf.buf.read_desc[i];
++ desc->ddadr = (hostdata->iobuf.buf.read_desc_phys_addr +
++ (i + 1) * sizeof( pxa_dma_desc))|DDADR_STOP;
++ desc->dsadr = MMC_RXFIFO_PHYS_ADDR;
++ desc->dtadr = hostdata->iobuf.buf.phys_addr + (i<<5);
++ desc->dcmd = DCMD_FLOWSRC|DCMD_INCTRGADDR
++ |DCMD_WIDTH1|DCMD_BURST32|(1<<5);
++
++ desc = &hostdata->iobuf.buf.write_desc[i];
++ desc->ddadr = (hostdata->iobuf.buf.write_desc_phys_addr +
++ (i + 1) * sizeof( pxa_dma_desc))|DDADR_STOP;
++ desc->dsadr = hostdata->iobuf.buf.phys_addr + (i<<5);
++ desc->dtadr = MMC_TXFIFO_PHYS_ADDR;
++ desc->dcmd = DCMD_FLOWTRG|DCMD_INCSRCADDR
++ |DCMD_WIDTH1|DCMD_BURST32|(1<<5);
++#endif
++/* II. MMC */
++/* 1) request irq */
++ if ( request_irq( IRQ_MMC, pxa_mmc_irq, 0, "MMC", ctrlr ) ) {
++ MMC_ERROR( "failed to request IRQ_MMC\n" );
++ goto error;
++ }
++
++/* 2) initialize h/w and ctrlr */
++ set_GPIO_mode( GPIO6_MMCCLK_MD );
++ CKEN |= CKEN12_MMC; /* enable MMC unit clock */
++
++ ret = 0;
++ goto out;
++error:
++#ifndef PIO
++/* free DMA resources */
++ if ( hostdata->iobuf.buf.chan >= 0 ) {
++ DRCMRRXMMC = 0;
++ DRCMRTXMMC = 0;
++ pxa_free_dma( hostdata->iobuf.buf.chan );
++ }
++ if ( hostdata->iobuf.iodata )
++ consistent_free( hostdata->iobuf.iodata,
++ PXA_MMC_IODATA_SIZE,
++ hostdata->iobuf.buf.phys_addr );
++ if ( hostdata->iobuf.buf.read_desc )
++ consistent_free( hostdata->iobuf.buf.read_desc,
++ (PXA_MMC_IODATA_SIZE>>5)
++ * sizeof( pxa_dma_desc ),
++ hostdata->iobuf.buf.read_desc_phys_addr );
++ if ( hostdata->iobuf.buf.write_desc )
++ consistent_free( hostdata->iobuf.buf.write_desc,
++ (PXA_MMC_IODATA_SIZE>>5)
++ * sizeof( pxa_dma_desc ),
++ hostdata->iobuf.buf.write_desc_phys_addr );
++#else
++ kfree( hostdata->iobuf.iodata );
++#endif
++out:
++ return ret;
++}
++
++static void pxa_mmc_remove( mmc_controller_t ctrlr )
++{
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++
++/* 1) free buffer(s) */
++#ifndef PIO
++ consistent_free( hostdata->iobuf.iodata, PXA_MMC_IODATA_SIZE,
++ hostdata->iobuf.buf.phys_addr );
++ consistent_free( hostdata->iobuf.buf.read_desc,
++ (PXA_MMC_IODATA_SIZE>>5)
++ * sizeof( pxa_dma_desc ),
++ hostdata->iobuf.buf.read_desc_phys_addr );
++ consistent_free( hostdata->iobuf.buf.write_desc,
++ (PXA_MMC_IODATA_SIZE>>5)
++ * sizeof( pxa_dma_desc ),
++ hostdata->iobuf.buf.write_desc_phys_addr );
++/* 2) release DMA channel */
++ if ( hostdata->iobuf.buf.chan >= 0 ) {
++ DRCMRRXMMC = 0;
++ DRCMRTXMMC = 0;
++ pxa_free_dma( hostdata->iobuf.buf.chan );
++ }
++#else
++ kfree( hostdata->iobuf.iodata );
++#endif
++/* II. MMC */
++/* 1) release irq */
++ free_irq( IRQ_MMC, ctrlr );
++ CKEN &= ~CKEN12_MMC; /* disable MMC unit clock */
++}
++
++static int pxa_mmc_probe( mmc_controller_t ctrlr )
++{
++ return 1;
++}
++
++#ifdef CONFIG_PM
++static int pxa_mmc_suspend( mmc_controller_t ctrlr )
++{
++ int ret = -EBUSY;
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "state=%s\n",
++ PXA_MMC_STATE_LABEL( hostdata->state ) );
++
++ if ( hostdata->state == PXA_MMC_FSM_IDLE ) {
++ /* save registers */
++ SAVED_MMC_CLKRT = MMC_CLKRT;
++ SAVED_MMC_RESTO = MMC_RESTO;
++ SAVED_MMC_SPI = MMC_SPI;
++ SAVED_DRCMRRXMMC = DRCMRRXMMC;
++ SAVED_DRCMRTXMMC = DRCMRTXMMC;
++
++#if 0 /* FIXME */
++ /* send CMD0 */
++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++ goto error;
++
++ MMC_CMD = CMD(0); /* CMD0 with zero argument */
++ MMC_ARGH = 0UL;
++ MMC_ARGL = 0UL;
++ MMC_CMDAT = 0UL;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD0(0x%04x%04x)\n", 0UL, 0UL );
++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_NORESPONSE,
++ FALSE )) )
++ {
++ ret = -EIO;
++ goto error;
++ }
++#endif
++
++ set_GPIO_mode( GPIO6_MMCCLK );
++ CKEN &= ~CKEN12_MMC; /* disable MMC unit clock */
++
++ hostdata->suspended = TRUE;
++ ret = 0;
++ }
++error:
++ return ret;
++}
++
++static void pxa_mmc_resume( mmc_controller_t ctrlr )
++{
++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++
++ if ( hostdata->suspended == TRUE ) {
++ set_GPIO_mode( GPIO6_MMCCLK_MD );
++ CKEN |= CKEN12_MMC; /* enable MMC unit clock */
++
++ /* restore registers */
++ MMC_CLKRT = SAVED_MMC_CLKRT;
++ MMC_RESTO = SAVED_MMC_RESTO;
++ MMC_SPI = SAVED_MMC_SPI;
++ DRCMRRXMMC = SAVED_DRCMRRXMMC;
++ DRCMRTXMMC = SAVED_DRCMRTXMMC;
++
++ hostdata->suspended = FALSE;
++
++ mmc_update_card_stack( ctrlr->slot ); /* FIXME */
++ }
++
++ return;
++}
++#endif
++
++static mmc_controller_tmpl_rec_t pxa_mmc_controller_tmpl_rec = {
++ owner: THIS_MODULE,
++ name: "PXA250",
++ block_size_max: PXA_MMC_BLKSZ_MAX,
++ nob_max: PXA_MMC_NOB_MAX,
++ probe: pxa_mmc_probe,
++ init: pxa_mmc_init,
++ remove: __devexit_p( pxa_mmc_remove ),
++#ifdef CONFIG_PM
++ suspend: pxa_mmc_suspend,
++ resume: pxa_mmc_resume,
++#endif /* CONFIG_PM */
++ update_acq: pxa_mmc_update_acq,
++// single_card_acq: pxa_mmc_single_card_acq,
++ init_card_stack: pxa_mmc_init_card_stack,
++ check_card_stack: pxa_mmc_check_card_stack,
++ setup_card: pxa_mmc_setup_card,
++ stream_read: pxa_mmc_stream_read,
++ read_block: pxa_mmc_read_block,
++ read_mblock: pxa_mmc_read_mblock,
++ stream_write: pxa_mmc_stream_write,
++ write_block: pxa_mmc_write_block,
++ write_mblock: pxa_mmc_write_mblock
++ /* TODO
++ sg_io: pxa_mmc_sg_io
++ */
++ /* TODO:
++ * erase,
++ * write protection,
++ * lock/password management methods
++ */
++};
++
++static int __devinit mmc_pxa_module_init( void )
++{
++ int ret = -ENODEV;
++#ifdef CONFIG_ARCH_RAMSES
++ RAMSES_MMC_ON();
++ udelay(1000);
++#endif
++
++ host = mmc_register( MMC_REG_TYPE_HOST, &pxa_mmc_controller_tmpl_rec,
++ sizeof( pxa_mmc_hostdata_rec_t ) );
++ if ( !host ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0,
++ "failed to register with MMC core\n" );
++ goto error;
++ }
++
++ ret = 0;
++error:
++ return ret;
++}
++
++static void __devexit mmc_pxa_module_cleanup( void )
++{
++ mmc_unregister( MMC_REG_TYPE_HOST, host );
++#ifdef CONFIG_ARCH_RAMSES
++ RAMSES_MMC_OFF();
++#endif
++}
++
++EXPORT_NO_SYMBOLS;
++
++MODULE_LICENSE( "GPL" );
++
++module_init( mmc_pxa_module_init );
++module_exit( mmc_pxa_module_cleanup );
+--- /dev/null
++++ linux-2.4.27/drivers/mmc/mmc_pxa.h
+@@ -0,0 +1,278 @@
++/*
++ * linux/drivers/mmc/mmc_pxa.h
++ *
++ * Author: Vladimir Shebordaev, Igor Oblakov
++ * Copyright: MontaVista Software Inc.
++ *
++ * $Id: mmc_pxa.h,v 0.3.1.6 2002/09/25 19:25:48 ted Exp ted $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef __MMC_PXA_P_H__
++#define __MMC_PXA_P_H__
++
++#include <linux/completion.h>
++
++#define PIO
++
++/* PXA-250 MMC controller registers */
++
++/* MMC_STRPCL */
++#define MMC_STRPCL_STOP_CLK (0x0001UL)
++#define MMC_STRPCL_START_CLK (0x0002UL)
++
++/* MMC_STAT */
++#define MMC_STAT_END_CMD_RES (0x0001UL << 13)
++#define MMC_STAT_PRG_DONE (0x0001UL << 12)
++#define MMC_STAT_DATA_TRAN_DONE (0x0001UL << 11)
++#define MMC_STAT_CLK_EN (0x0001UL << 8)
++#define MMC_STAT_RECV_FIFO_FULL (0x0001UL << 7)
++#define MMC_STAT_XMIT_FIFO_EMPTY (0x0001UL << 6)
++#define MMC_STAT_RES_CRC_ERROR (0x0001UL << 5)
++#define MMC_STAT_SPI_READ_ERROR_TOKEN (0x0001UL << 4)
++#define MMC_STAT_CRC_READ_ERROR (0x0001UL << 3)
++#define MMC_STAT_CRC_WRITE_ERROR (0x0001UL << 2)
++#define MMC_STAT_TIME_OUT_RESPONSE (0x0001UL << 1)
++#define MMC_STAT_READ_TIME_OUT (0x0001UL)
++
++#define MMC_STAT_ERRORS (MMC_STAT_RES_CRC_ERROR|MMC_STAT_SPI_READ_ERROR_TOKEN\
++ |MMC_STAT_CRC_READ_ERROR|MMC_STAT_TIME_OUT_RESPONSE\
++ |MMC_STAT_READ_TIME_OUT)
++
++/* MMC_CLKRT */
++#define MMC_CLKRT_20MHZ (0x0000UL)
++#define MMC_CLKRT_10MHZ (0x0001UL)
++#define MMC_CLKRT_5MHZ (0x0002UL)
++#define MMC_CLKRT_2_5MHZ (0x0003UL)
++#define MMC_CLKRT_1_25MHZ (0x0004UL)
++#define MMC_CLKRT_0_625MHZ (0x0005UL)
++#define MMC_CLKRT_0_3125MHZ (0x0006UL)
++
++/* MMC_SPI */
++#define MMC_SPI_DISABLE (0x00UL)
++#define MMC_SPI_EN (0x01UL)
++#define MMC_SPI_CS_EN (0x01UL << 2)
++#define MMC_SPI_CS_ADDRESS (0x01UL << 3)
++#define MMC_SPI_CRC_ON (0x01UL << 1)
++
++/* MMC_CMDAT */
++#define MMC_CMDAT_MMC_DMA_EN (0x0001UL << 7)
++#define MMC_CMDAT_INIT (0x0001UL << 6)
++#define MMC_CMDAT_BUSY (0x0001UL << 5)
++#define MMC_CMDAT_STREAM (0x0001UL << 4)
++#define MMC_CMDAT_BLOCK (0x0000UL << 4)
++#define MMC_CMDAT_WRITE (0x0001UL << 3)
++#define MMC_CMDAT_READ (0x0000UL << 3)
++#define MMC_CMDAT_DATA_EN (0x0001UL << 2)
++#define MMC_CMDAT_R1 (0x0001UL)
++#define MMC_CMDAT_R2 (0x0002UL)
++#define MMC_CMDAT_R3 (0x0003UL)
++
++/* MMC_RESTO */
++#define MMC_RES_TO_MAX (0x007fUL) /* [6:0] */
++
++/* MMC_RDTO */
++#define MMC_READ_TO_MAX (0x0ffffUL) /* [15:0] */
++
++/* MMC_BLKLEN */
++#define MMC_BLK_LEN_MAX (0x03ffUL) /* [9:0] */
++
++/* MMC_PRTBUF */
++#define MMC_PRTBUF_BUF_PART_FULL (0x01UL)
++#define MMC_PRTBUF_BUF_FULL (0x00UL )
++
++/* MMC_I_MASK */
++#define MMC_I_MASK_TXFIFO_WR_REQ (0x01UL << 6)
++#define MMC_I_MASK_RXFIFO_RD_REQ (0x01UL << 5)
++#define MMC_I_MASK_CLK_IS_OFF (0x01UL << 4)
++#define MMC_I_MASK_STOP_CMD (0x01UL << 3)
++#define MMC_I_MASK_END_CMD_RES (0x01UL << 2)
++#define MMC_I_MASK_PRG_DONE (0x01UL << 1)
++#define MMC_I_MASK_DATA_TRAN_DONE (0x01UL)
++#define MMC_I_MASK_ALL (0x07fUL)
++
++
++/* MMC_I_REG */
++#define MMC_I_REG_TXFIFO_WR_REQ (0x01UL << 6)
++#define MMC_I_REG_RXFIFO_RD_REQ (0x01UL << 5)
++#define MMC_I_REG_CLK_IS_OFF (0x01UL << 4)
++#define MMC_I_REG_STOP_CMD (0x01UL << 3)
++#define MMC_I_REG_END_CMD_RES (0x01UL << 2)
++#define MMC_I_REG_PRG_DONE (0x01UL << 1)
++#define MMC_I_REG_DATA_TRAN_DONE (0x01UL)
++#define MMC_I_REG_ALL (0x007fUL)
++
++/* MMC_CMD */
++#define MMC_CMD_INDEX_MAX (0x006fUL) /* [5:0] */
++#define CMD(x) (x)
++
++/* MMC_ARGH */
++/* MMC_ARGL */
++/* MMC_RES */
++/* MMC_RXFIFO */
++#define MMC_RXFIFO_PHYS_ADDR 0x41100040 //MMC_RXFIFO physical address
++/* MMC_TXFIFO */
++#define MMC_TXFIFO_PHYS_ADDR 0x41100044 //MMC_TXFIFO physical address
++
++/* implementation specific declarations */
++#define PXA_MMC_BLKSZ_MAX (1<<9) /* actually 1023 */
++#define PXA_MMC_NOB_MAX ((1<<16)-2)
++#define PXA_MMC_BLOCKS_PER_BUFFER (2)
++
++#define PXA_MMC_IODATA_SIZE (PXA_MMC_BLOCKS_PER_BUFFER*PXA_MMC_BLKSZ_MAX) /* 1K */
++
++typedef enum _pxa_mmc_fsm { /* command processing FSM */
++ PXA_MMC_FSM_IDLE = 1,
++ PXA_MMC_FSM_CLK_OFF,
++ PXA_MMC_FSM_END_CMD,
++ PXA_MMC_FSM_BUFFER_IN_TRANSIT,
++ PXA_MMC_FSM_END_BUFFER,
++ PXA_MMC_FSM_END_IO,
++ PXA_MMC_FSM_END_PRG,
++ PXA_MMC_FSM_ERROR
++} pxa_mmc_state_t;
++
++#define PXA_MMC_STATE_LABEL( state ) (\
++ (state == PXA_MMC_FSM_IDLE) ? "IDLE" :\
++ (state == PXA_MMC_FSM_CLK_OFF) ? "CLK_OFF" :\
++ (state == PXA_MMC_FSM_END_CMD) ? "END_CMD" :\
++ (state == PXA_MMC_FSM_BUFFER_IN_TRANSIT) ? "IN_TRANSIT" :\
++ (state == PXA_MMC_FSM_END_BUFFER) ? "END_BUFFER" :\
++ (state == PXA_MMC_FSM_END_IO) ? "END_IO" :\
++ (state == PXA_MMC_FSM_END_PRG) ? "END_PRG" : "UNKNOWN" )
++
++typedef enum _pxa_mmc_result {
++ PXA_MMC_NORMAL = 0,
++ PXA_MMC_INVALID_STATE = -1,
++ PXA_MMC_TIMEOUT = -2,
++ PXA_MMC_ERROR = -3
++} pxa_mmc_result_t;
++
++typedef u32 pxa_mmc_clkrt_t;
++
++typedef char *pxa_mmc_iodata_t;
++#ifdef PIO
++typedef struct _pxa_mmc_piobuf_rec {
++ char *pos; /* current buffer position */
++ int cnt; /* byte counter */
++} pxa_mmc_piobuf_rec_t, *pxa_mmc_piobuf_t;
++#else /* i.e. DMA */
++typedef struct _pxa_mmc_dmabuf_rec { /* TODO: buffer ring, DMA irq completion */
++ int chan; /* dma channel no */
++ dma_addr_t phys_addr; /* iodata physical address */
++ pxa_dma_desc *read_desc; /* input descriptor array virtual address */
++ pxa_dma_desc *write_desc; /* output descriptor array virtual address */
++ dma_addr_t read_desc_phys_addr; /* descriptor array physical address */
++ dma_addr_t write_desc_phys_addr; /* descriptor array physical address */
++ pxa_dma_desc *last_read_desc; /* last input descriptor
++ * used by the previous transfer
++ */
++ pxa_dma_desc *last_write_desc; /* last output descriptor
++ * used by the previous transfer
++ */
++} pxa_mmc_dmabuf_rec_t, *pxa_mmc_dmabuf_t;
++#endif
++
++typedef struct _pxa_mmc_iobuf_rec {
++ ssize_t blksz; /* current block size in bytes */
++ ssize_t bufsz; /* buffer size for each transfer */
++ ssize_t nob; /* number of blocks pers buffer */
++#ifndef PIO
++ pxa_mmc_dmabuf_rec_t buf; /* i.e. DMA buffer ring on the iodata */
++#else /* i.e. DMA */
++ pxa_mmc_piobuf_rec_t buf; /* PIO buffer accounting */
++#endif
++ pxa_mmc_iodata_t iodata; /* I/O data buffer */
++} pxa_mmc_iobuf_rec_t, *pxa_mmc_iobuf_t;
++
++typedef struct _pxa_mmc_hostdata_rec {
++ pxa_mmc_state_t state; /* FSM */
++#ifdef CONFIG_PM
++ int suspended;
++#endif
++ pxa_mmc_iobuf_rec_t iobuf; /* data transfer state */
++
++ int busy; /* atomic busy flag */
++ struct completion completion; /* completion */
++#if CONFIG_MMC_DEBUG_IRQ
++ int irqcnt;
++ int timeo;
++#endif
++
++/* cached controller state */
++ u32 mmc_i_reg; /* interrupt last requested */
++ u32 mmc_i_mask; /* mask to be set by intr handler */
++ u32 mmc_stat; /* status register at the last intr */
++ u32 mmc_cmdat; /* MMC_CMDAT at the last inr */
++ u8 mmc_res[16]; /* response to the last command in host order */
++ u32 saved_mmc_clkrt;
++ u32 saved_mmc_resto;
++ u32 saved_mmc_spi;
++ u32 saved_drcmrrxmmc;
++ u32 saved_drcmrtxmmc;
++
++/* controller options */
++ pxa_mmc_clkrt_t clkrt; /* current bus clock rate */
++} pxa_mmc_hostdata_rec_t, *pxa_mmc_hostdata_t;
++
++#define PXA_MMC_STATUS( ctrlr ) (((pxa_mmc_hostdata_t)ctrlr->host_data)->mmc_stat)
++#define PXA_MMC_RESPONSE( ctrlr, idx ) ((((pxa_mmc_hostdata_t)ctrlr->host_data)->mmc_res)[idx])
++#define PXA_MMC_CLKRT( ctrlr ) (((pxa_mmc_hostdata_t)ctrlr->host_data)->clkrt)
++
++#define SAVED_MMC_CLKRT (hostdata->saved_mmc_clkrt)
++#define SAVED_MMC_RESTO (hostdata->saved_mmc_resto)
++#define SAVED_MMC_SPI (hostdata->saved_mmc_spi)
++#define SAVED_DRCMRRXMMC (hostdata->saved_drcmrrxmmc )
++#define SAVED_DRCMRTXMMC (hostdata->saved_drcmrtxmmc )
++
++static inline int pxa_mmc_clkrt( int speed )
++{
++ return MMC_CLKRT_20MHZ; /* TODO */
++}
++
++/* PXA MMC controller specific card data */
++typedef struct _pxa_mmc_card_data_rec {
++ pxa_mmc_clkrt_t clkrt; /* clock rate to be set for the card */
++} pxa_mmc_card_data_rec_t, *pxa_mmc_card_data_t;
++
++#ifdef CONFIG_MMC_DEBUG
++#undef MMC_DUMP_R1
++#undef MMC_DUMP_R2
++#undef MMC_DUMP_R3
++#define MMC_DUMP_R2( ctrlr ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \
++"R2 response: %02x %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", \
++PXA_MMC_RESPONSE( ctrlr, 15 ), \
++PXA_MMC_RESPONSE( ctrlr, 14 ), \
++PXA_MMC_RESPONSE( ctrlr, 13 ), \
++PXA_MMC_RESPONSE( ctrlr, 12 ), \
++PXA_MMC_RESPONSE( ctrlr, 11 ), \
++PXA_MMC_RESPONSE( ctrlr, 10 ), \
++PXA_MMC_RESPONSE( ctrlr, 9 ), \
++PXA_MMC_RESPONSE( ctrlr, 8 ), \
++PXA_MMC_RESPONSE( ctrlr, 7 ), \
++PXA_MMC_RESPONSE( ctrlr, 6 ), \
++PXA_MMC_RESPONSE( ctrlr, 5 ), \
++PXA_MMC_RESPONSE( ctrlr, 4 ), \
++PXA_MMC_RESPONSE( ctrlr, 3 ), \
++PXA_MMC_RESPONSE( ctrlr, 2 ), \
++PXA_MMC_RESPONSE( ctrlr, 1 ), \
++PXA_MMC_RESPONSE( ctrlr, 0 ) );
++#define MMC_DUMP_R1( ctrlr ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \
++"R1(b) response: %02x %02x%02x%02x%02x\n", \
++PXA_MMC_RESPONSE( ctrlr, 5 ), \
++PXA_MMC_RESPONSE( ctrlr, 4 ), \
++PXA_MMC_RESPONSE( ctrlr, 3 ), \
++PXA_MMC_RESPONSE( ctrlr, 2 ), \
++PXA_MMC_RESPONSE( ctrlr, 1 ) );
++#define MMC_DUMP_R3( ctrlr ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \
++"R3 response: %02x %02x%02x%02x%02x\n", \
++PXA_MMC_RESPONSE( ctrlr, 5 ), \
++PXA_MMC_RESPONSE( ctrlr, 4 ), \
++PXA_MMC_RESPONSE( ctrlr, 3 ), \
++PXA_MMC_RESPONSE( ctrlr, 2 ), \
++PXA_MMC_RESPONSE( ctrlr, 1 ) );
++
++#endif
++#endif /* __MMC_PXA_P_H__ */
+--- /dev/null
++++ linux-2.4.27/drivers/mmc/mmc_test.c
+@@ -0,0 +1,538 @@
++/*
++ * linux/drivers/mmc/mmc_test.c
++ *
++ * Author: Vladimir Shebordaev
++ * Copyright: MontaVista Software Inc.
++ *
++ * $Id: mmc_test.c,v 0.4 2002/08/01 12:26:40 ted Exp ted $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++
++#include <linux/fs.h>
++#ifdef CONFIG_DEVFS_FS
++#include <linux/devfs_fs_kernel.h>
++#endif
++
++#include <asm/uaccess.h>
++
++#include <mmc/types.h>
++#include <mmc/mmc.h>
++#include <mmc/ioctl.h>
++
++#include "types.h"
++#include "mmc.h"
++
++typedef struct _mmc_test_device_rec mmc_test_device_rec_t;
++typedef struct _mmc_test_device_rec *mmc_test_device_t;
++
++struct _mmc_test_device_rec {
++ mmc_card_t card;
++ mmc_transfer_mode_t transfer_mode;
++ int usage;
++#ifdef CONFIG_DEVFS_FS
++ devfs_handle_t devfs_handle;
++#endif
++};
++
++/* MMC device table */
++static mmc_test_device_rec_t mmc_test_device[MMC_CONTROLLERS_MAX][MMC_CARDS_MAX];
++static DECLARE_MUTEX(mmc_test_device_mutex);
++
++static inline mmc_test_device_t __mmc_test_get_device( kdev_t rdev )
++{
++ mmc_test_device_t ret = NULL;
++ u8 minor = MINOR( rdev );
++ int host_no, card_no;
++
++ host_no = minor >> MMC_MINOR_HOST_SHIFT;
++ if ( host_no >= MMC_CONTROLLERS_MAX )
++ goto error;
++
++ card_no = minor & MMC_MINOR_CARD_MASK;
++ if ( card_no >= MMC_CARDS_MAX )
++ goto error;
++
++ ret = &mmc_test_device[host_no][card_no];
++ if ( !ret->card ) {
++ ret->card = mmc_get_card( host_no, card_no );
++ if ( !ret->card ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to get card: host=%d, card=%d\n", host_no, card_no );
++ ret = NULL;
++ goto error;
++ }
++
++ }
++ ++ret->usage;
++
++error:
++ return ret;
++}
++
++static inline void __mmc_test_put_device( mmc_test_device_t dev )
++{
++ mmc_put_card( dev->card );
++ --dev->usage;
++}
++
++static inline mmc_test_device_t mmc_test_get_device( kdev_t kdev )
++{
++ mmc_test_device_t ret = NULL;
++
++ down( &mmc_test_device_mutex );
++ ret = __mmc_test_get_device( kdev );
++ up( &mmc_test_device_mutex );
++
++ return ret;
++}
++
++static inline void mmc_test_put_device( mmc_test_device_t dev )
++{
++ if ( dev ) {
++ down( &mmc_test_device_mutex );
++ __mmc_test_put_device( dev );
++ if ( !dev->usage ) {
++ if ( dev->card ) {
++ if ( dev->card->usage ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0,
++ "broken card reference\n" );
++ }
++ memset( dev, 0, sizeof( mmc_test_device_rec_t ) );
++ }
++ }
++ up( &mmc_test_device_mutex );
++ }
++}
++
++static inline int mmc_test_set_transfer_mode( mmc_test_device_t dev, mmc_transfer_mode_t mode )
++{
++ int ret = -1;
++
++ if ( dev ) {
++ down( &mmc_test_device_mutex );
++ dev->transfer_mode = mode;
++ ret = 0;
++ up( &mmc_test_device_mutex );
++ }
++ return ret;
++}
++
++static inline mmc_transfer_mode_t mmc_test_get_transfer_mode( mmc_test_device_t dev )
++{
++ mmc_transfer_mode_t ret = MMC_TRANSFER_MODE_UNDEFINED;
++
++ if ( dev ) {
++ down( &mmc_test_device_mutex );
++ ret = dev->transfer_mode;
++ up( &mmc_test_device_mutex );
++ }
++ return ret;
++}
++
++static int mmc_test_open( struct inode *inode, struct file *file )
++{
++ int ret = -ENODEV;
++ mmc_test_device_t dev = NULL;
++
++ MOD_INC_USE_COUNT;
++
++ __ENTER0( );
++ dev = mmc_test_get_device( inode->i_rdev );
++ if ( !dev || !dev->card ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to acquire device\n" );
++ goto error;
++ }
++
++ if ( dev->card->usage > 1 ) {
++ ret = -EBUSY;
++ goto error;
++ }
++
++ dev->transfer_mode = MMC_TEST_TRANSFER_MODE_DEFAULT; /* FIXME: should check card CCC */
++ file->private_data = dev;
++
++ __LEAVE0( );
++ return 0;
++error:
++ MOD_DEC_USE_COUNT;
++ mmc_test_put_device( dev );
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++static int mmc_test_release( struct inode *inode, struct file *file )
++{
++ int ret = -ENODEV;
++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data;
++
++ if ( !dev ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" );
++ goto error;
++ }
++
++ __ENTER( "host=%d, card=%d", dev->card->ctrlr->slot, dev->card->slot );
++
++ file->private_data = NULL;
++
++ mmc_test_put_device( dev );
++ MOD_DEC_USE_COUNT;
++
++ ret = 0;
++error:
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++static ssize_t mmc_test_read( struct file *file, char *buf, size_t size, loff_t *ppos )
++{
++ ssize_t ret = -ENODEV;
++ ssize_t retsize = 0;
++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data;
++
++ __ENTER( "host=%d, card=%d, size=%d", dev->card->ctrlr->slot, dev->card->slot, size );
++
++ if ( !dev ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" );
++ goto error;
++ }
++
++ switch ( dev->transfer_mode ) {
++ char *mbuf;
++
++ case MMC_TRANSFER_MODE_BLOCK_SINGLE:
++ mbuf = kmalloc( 512, GFP_ATOMIC ); /* FIXME: actual read_bl_len or ctrlr->block_size_max whichever is less ), GFP_KERNEL */
++ if ( !mbuf ) {
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ while( size > 0 ) {
++ int lsize = (size > 512) ? 512 : size;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL4,
++ "before mmc_read mbuf=0x%x "
++ "lsize=%d ppos=0x%x *ppos=%d\n",
++ mbuf, lsize, ppos, *ppos );
++ ret = mmc_read( dev->card,
++ MMC_TRANSFER_MODE_BLOCK_SINGLE,
++ mbuf, lsize, ppos );
++ if ( ret <= 0 )
++ break;
++
++ /* Copy to user */
++ if ( copy_to_user( buf, mbuf, ret ) ) {
++ ret = -EFAULT;
++ break;
++ }
++ retsize += ret;
++ buf += ret;
++ size -= ret;
++ }
++
++ if ( retsize > 0 )
++ ret = retsize;
++ kfree(mbuf);
++ break;
++
++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE:
++ mbuf = kmalloc( 1024, GFP_ATOMIC ); /* FIXME */
++ if ( !mbuf ) {
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ while( size > 0 ) {
++ int lsize = (size > 1024) ? 1024 : size;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL4,
++ "before mmc_read mbuf=0x%x "
++ "lsize=%d ppos=0x%x *ppos=%d\n",
++ mbuf, lsize, ppos, *ppos );
++ ret = mmc_read( dev->card,
++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE,
++ mbuf, lsize, ppos );
++ if ( ret <= 0 )
++ break;
++
++ /* Copy to user */
++ if ( copy_to_user( buf, mbuf, ret ) ) {
++ ret = -EFAULT;
++ break;
++ }
++ retsize += ret;
++ buf += ret;
++ size -= ret;
++ }
++
++ if ( retsize > 0 )
++ ret = retsize;
++ kfree(mbuf);
++ break;
++
++ case MMC_TRANSFER_MODE_STREAM:
++ ret = mmc_read( dev->card, dev->transfer_mode,
++ buf, size, ppos );
++ break;
++
++ default:
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid transfer mode\n" );
++ }
++error:
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++static ssize_t mmc_test_write( struct file *file, const char *buf, size_t size, loff_t *ppos )
++{
++ ssize_t ret = -ENODEV;
++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data;
++ int retsize=0;
++
++ __ENTER( "host=%d, card=%d, size=%d", dev->card->ctrlr->slot, dev->card->slot, size );
++
++ if ( !dev ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" );
++ goto error;
++ }
++
++ switch ( dev->transfer_mode ) {
++ char *mbuf;
++
++ case MMC_TRANSFER_MODE_BLOCK_SINGLE:
++ mbuf = kmalloc( 512, GFP_ATOMIC ); /* FIXME: actual write_bl_len or ctrlr->block_size_max whichever is less, GFP_KERNEL */
++ if ( !mbuf ) {
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ while ( size > 0 ) {
++ int lsize = ( size > 512 ) ? 512 : size;
++
++ /* Copy from user */
++ if ( copy_from_user( mbuf, buf, lsize ) ) {
++ ret = -EFAULT;
++ break;
++ }
++
++ ret = mmc_write( dev->card,
++ MMC_TRANSFER_MODE_BLOCK_SINGLE,
++ mbuf, lsize, ppos );
++ if( ret <= 0 )
++ break;
++
++ retsize += ret;
++ buf += ret;
++ size -= ret;
++ }
++
++ if ( retsize > 0 )
++ ret = retsize;
++
++ kfree( mbuf );
++ break;
++
++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE:
++ mbuf = kmalloc( 1024, GFP_ATOMIC ); /* FIXME */
++ if ( !mbuf ) {
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ while( size > 0 ) {
++ int lsize = (size > 1024) ? 1024 : size;
++
++ MMC_DEBUG( MMC_DEBUG_LEVEL4,
++ "before mmc_read mbuf=0x%x "
++ "lsize=%d ppos=0x%x *ppos=%d\n",
++ mbuf, lsize, ppos, *ppos );
++ ret = mmc_write( dev->card,
++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE,
++ mbuf, lsize, ppos );
++ if ( ret <= 0 )
++ break;
++
++ /* Copy to user */
++ if ( copy_to_user( (char *)buf, mbuf, ret ) ) {
++ ret = -EFAULT;
++ break;
++ }
++ retsize += ret;
++ buf += ret;
++ size -= ret;
++ }
++
++ if ( retsize > 0 )
++ ret = retsize;
++ kfree(mbuf);
++ break;
++ case MMC_TRANSFER_MODE_STREAM:
++ ret = mmc_write( dev->card, dev->transfer_mode,
++ buf, size, ppos );
++ break;
++
++ default:
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid transfer mode\n" );
++ }
++error:
++ __LEAVE( "ret=%d", ret );
++ return ret;
++}
++
++static loff_t mmc_test_llseek( struct file *file, loff_t offset, int origin )
++{
++ loff_t ret = -ESPIPE;
++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data;
++ mmc_card_t card;
++
++ if ( !dev ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" );
++ ret = -ENODEV;
++ goto error;
++ }
++
++ __ENTER( "host=%d, card=%d, off=%ld, orig=%d", dev->card->ctrlr->slot, dev->card->slot, (long)offset, origin );
++
++ card = dev->card;
++
++ switch ( origin ) {
++ case SEEK_CUR:
++ file->f_pos += offset;
++ break;
++
++ case SEEK_END:
++ file->f_pos = card->info.capacity + offset;
++ break;
++
++ case SEEK_SET:
++ file->f_pos = offset;
++ break;
++
++ default:
++ ret = -EINVAL;
++ goto error;
++ }
++
++ ret = file->f_pos;
++error:
++ __LEAVE( "ret=%ld", (long)ret );
++ return ret;
++}
++
++static int mmc_test_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg )
++{
++ int ret = -ENODEV;
++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data;
++
++ if ( !dev ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" );
++ goto error;
++ }
++
++ switch ( cmd ) {
++ case IOCMMCSTRNSMODE:
++ if ( get_user( ret, (int *)arg ) ) {
++ ret = -EFAULT;
++ goto error;
++ }
++ ret = mmc_test_set_transfer_mode( dev, ret );
++ break;
++
++ case IOCMMCGTRNSMODE:
++ ret = mmc_test_get_transfer_mode( dev );
++ if ( put_user( ret, (int *)arg ) )
++ ret = -EFAULT;
++ break;
++
++ default:
++ ret = mmc_ioctl( dev->card, cmd, arg );
++ }
++
++error:
++ return ret;
++}
++
++struct file_operations mmc_test_fops = {
++ owner: THIS_MODULE,
++ open: mmc_test_open,
++ release: mmc_test_release,
++ read: mmc_test_read,
++ write: mmc_test_write,
++ ioctl: mmc_test_ioctl,
++ llseek: mmc_test_llseek
++};
++
++#ifdef CONFIG_DEVFS_FS
++static int mmc_test_add_card( mmc_card_t card ) /* TODO */
++{
++ int ret = -1;
++ __ENTER( "host=%d, card=%d", card->ctrlr->slot, card->slot );
++/* TODO: make kdev; register with devfs */
++ __LEAVE0( );
++ return ret;
++}
++
++static int mmc_test_remove_card( mmc_card_t card ) /* TODO */
++{
++ int ret = -1;
++ __ENTER( "host=%d, card=%d", card->ctrlr->slot, card->slot );
++/* TODO: make kdev; unregister with devfs */
++ __LEAVE0( );
++ return ret;
++}
++
++static mmc_notifier_rec_t mmc_test_notifier = {
++ add: mmc_test_add_card,
++ remove: mmc_test_remove_card
++};
++#endif /* CONFIG_DEVFS_FS */
++
++static int __init mmc_test_module_init( void )
++{
++ int ret = -ENODEV;
++
++#ifdef CONFIG_DEVFS_FS
++ if ( !mmc_register( MMC_REG_TYPE_USER, &mmc_test_notifier, 0 ) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register with MMC core\n" );
++ goto error;
++ }
++#else
++ mmc_register( MMC_REG_TYPE_USER, NULL, 0 );
++ if ( register_chrdev( MMC_TEST_MAJOR, "mmc_test", &mmc_test_fops ) ) {
++ MMC_DEBUG( MMC_DEBUG_LEVEL0,
++ "failed to request device major number\n" );
++ mmc_unregister( MMC_REG_TYPE_USER, NULL );
++ goto error;
++ }
++#endif
++
++ memset( mmc_test_device, 0, sizeof( mmc_test_device ) );
++
++ ret = 0;
++error:
++ return ret;
++}
++
++static void __exit mmc_test_module_cleanup( void )
++{
++#ifdef CONFIG_DEVFS_FS
++ mmc_unregister( MMC_REG_TYPE_USER, &mmc_test_notifier );
++#else
++ mmc_unregister( MMC_REG_TYPE_USER, NULL );
++ unregister_chrdev( MMC_TEST_MAJOR, "mmc_test" );
++#endif
++}
++
++EXPORT_NO_SYMBOLS;
++
++module_init( mmc_test_module_init );
++module_exit( mmc_test_module_cleanup );
++
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ linux-2.4.27/drivers/mmc/pm_test.c
+@@ -0,0 +1,29 @@
++/* Power Managment Test Module. RTSoft Co. 2002 */
++
++/* The necessary header files */
++
++/* Standard in kernel modules */
++#include <linux/kernel.h> /* We're doing kernel work */
++#include <linux/module.h> /* Specifically, a module */
++#define CONFIG_PM
++#include <linux/pm.h>
++
++
++static int pmdata = -1;
++
++/* Initialize the module - register the proc file */
++
++int init_module()
++{
++ pm_send_all(PM_SUSPEND,&pmdata);
++ return(0);
++}
++
++
++/* Cleanup - unregister our file from /proc */
++void cleanup_module()
++{
++ pm_send_all(PM_RESUME,NULL);
++}
++
++MODULE_LICENSE( "GPL" );
+--- /dev/null
++++ linux-2.4.27/drivers/mmc/types.h
+@@ -0,0 +1,59 @@
++/*
++ * linux/drivers/mmc/types.h
++ *
++ * Author: Vladimir Shebordaev
++ * Copyright: MontaVista Software Inc.
++ *
++ * $Id: types.h,v 0.5 2002/08/13 17:34:02 ted Exp ted $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef __MMC_TYPES_P_H__
++#define __MMC_TYPES_P_H__
++
++#ifdef __KERNEL__
++#include <linux/kdev_t.h>
++
++typedef enum _mmc_reg_type mmc_reg_type_t;
++typedef enum _mmc_response mmc_response_fmt_t;
++
++/* MMC card private description */
++typedef struct _mmc_card_rec mmc_card_rec_t;
++typedef struct _mmc_card_rec *mmc_card_t;
++typedef enum _mmc_dir mmc_dir_t;
++typedef enum _mmc_buftype mmc_buftype_t;
++
++/* notifier declarations */
++typedef struct _mmc_notifier_rec mmc_notifier_rec_t;
++typedef struct _mmc_notifier_rec *mmc_notifier_t;
++
++typedef int (*mmc_notifier_fn_t) ( mmc_card_t );
++
++/* MMC card stack */
++typedef struct _mmc_card_stack_rec mmc_card_stack_rec_t;
++typedef struct _mmc_card_stack_rec *mmc_card_stack_t;
++
++typedef struct _mmc_data_transfer_req_rec mmc_data_transfer_req_rec_t;
++typedef struct _mmc_data_transfer_req_rec *mmc_data_transfer_req_t;
++
++/* MMC controller */
++typedef struct _mmc_controller_tmpl_rec mmc_controller_tmpl_rec_t;
++typedef struct _mmc_controller_tmpl_rec *mmc_controller_tmpl_t;
++
++typedef enum _mmc_controller_state mmc_controller_state_t;
++typedef struct _mmc_controller_rec mmc_controller_rec_t;
++typedef struct _mmc_controller_rec *mmc_controller_t;
++
++/* various kernel types */
++typedef struct semaphore semaphore_t;
++typedef struct rw_semaphore rwsemaphore_t;
++typedef struct proc_dir_entry proc_dir_entry_rec_t;
++typedef struct proc_dir_entry *proc_dir_entry_t;
++typedef struct gendisk gendisk_rec_t;
++typedef struct gendisk *gendisk_t;
++#endif /* __KERNEL__ */
++
++#endif /* __MMC_TYPES_P_H__ */
++
+--- linux-2.4.27/drivers/mtd/maps/Config.in~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/mtd/maps/Config.in
+@@ -75,6 +75,7 @@
+ fi
+
+ 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 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.27/drivers/mtd/maps/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/mtd/maps/Makefile
+@@ -15,6 +15,9 @@
+ obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o
+ obj-$(CONFIG_MTD_EPXA) += epxa-flash.o
+ obj-$(CONFIG_MTD_IQ80310) += iq80310.o
++obj-$(CONFIG_MTD_LUBBOCK) += lubbock.o
++obj-$(CONFIG_MTD_PXA_CERF) += pxa_cerf.o
++obj-$(CONFIG_MTD_TRIZEPS2) += trizeps2.o
+ obj-$(CONFIG_MTD_L440GX) += l440gx.o
+ obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
+ obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o
+--- /dev/null
++++ linux-2.4.27/drivers/mtd/maps/lubbock.c
+@@ -0,0 +1,168 @@
++/*
++ * $Id:
++ *
++ * Map driver for the Lubbock developer platform.
++ *
++ * Author: Nicolas Pitre
++ * Copyright: (C) 2001 MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <asm/io.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++
++#define WINDOW_ADDR 0
++//#define WINDOW_ADDR 0x04000000
++#define WINDOW_SIZE 64*1024*1024
++
++static __u8 lubbock_read8(struct map_info *map, unsigned long ofs)
++{
++ return *(__u8 *)(map->map_priv_1 + ofs);
++}
++
++static __u16 lubbock_read16(struct map_info *map, unsigned long ofs)
++{
++ return *(__u16 *)(map->map_priv_1 + ofs);
++}
++
++static __u32 lubbock_read32(struct map_info *map, unsigned long ofs)
++{
++ return *(__u32 *)(map->map_priv_1 + ofs);
++}
++
++static void lubbock_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 lubbock_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ *(__u8 *)(map->map_priv_1 + adr) = d;
++}
++
++static void lubbock_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ *(__u16 *)(map->map_priv_1 + adr) = d;
++}
++
++static void lubbock_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ *(__u32 *)(map->map_priv_1 + adr) = d;
++}
++
++static void lubbock_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 lubbock_map = {
++ name: "Lubbock flash",
++ size: WINDOW_SIZE,
++ read8: lubbock_read8,
++ read16: lubbock_read16,
++ read32: lubbock_read32,
++ copy_from: lubbock_copy_from,
++ write8: lubbock_write8,
++ write16: lubbock_write16,
++ write32: lubbock_write32,
++ copy_to: lubbock_copy_to
++};
++
++static struct mtd_partition lubbock_partitions[] = {
++ {
++ name: "Bootloader",
++ size: 0x00040000,
++ offset: 0,
++ mask_flags: MTD_WRITEABLE /* force read-only */
++ },{
++ name: "Kernel",
++ size: 0x00100000,
++ offset: 0x00040000,
++ },{
++ name: "Filesystem",
++ size: MTDPART_SIZ_FULL,
++ offset: 0x00140000
++ }
++};
++
++#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_lubbock(void)
++{
++ struct mtd_partition *parts;
++ int nb_parts = 0;
++ int parsed_nr_parts = 0;
++ char *part_type = "static";
++
++ lubbock_map.buswidth = (BOOT_DEF & 1) ? 2 : 4;
++ printk( "Probing Lubbock flash at physical address 0x%08x (%d-bit buswidth)\n",
++ WINDOW_ADDR, lubbock_map.buswidth * 8 );
++ lubbock_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0);
++ if (!lubbock_map.map_priv_1) {
++ printk("Failed to ioremap\n");
++ return -EIO;
++ }
++ mymtd = do_map_probe("cfi_probe", &lubbock_map);
++ if (!mymtd) {
++ iounmap((void *)lubbock_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 = lubbock_partitions;
++ nb_parts = NB_OF(lubbock_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_lubbock(void)
++{
++ if (mymtd) {
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
++ if (parsed_parts)
++ kfree(parsed_parts);
++ }
++ if (lubbock_map.map_priv_1)
++ iounmap((void *)lubbock_map.map_priv_1);
++ return 0;
++}
++
++module_init(init_lubbock);
++module_exit(cleanup_lubbock);
++
+--- /dev/null
++++ linux-2.4.27/drivers/mtd/maps/pxa_cerf.c
+@@ -0,0 +1,172 @@
++/*
++ * Map driver for the PXA Cerf.
++ *
++ * 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
++#if defined (CONFIG_PXA_CERF_FLASH_64MB)
++#define WINDOW_SIZE 64*1024*1024
++#elif defined (CONFIG_PXA_CERF_FLASH_32MB)
++#define WINDOW_SIZE 32*1024*1024
++#elif defined (CONFIG_PXA_CERF_FLASH_16MB)
++#define WINDOW_SIZE 16*1024*1024
++#endif
++#define BUSWIDTH 4
++
++static __u8 pxa_cerf_read8(struct map_info *map, unsigned long ofs)
++{
++ return *(__u8 *)(map->map_priv_1 + ofs);
++}
++
++static __u16 pxa_cerf_read16(struct map_info *map, unsigned long ofs)
++{
++ return *(__u16 *)(map->map_priv_1 + ofs);
++}
++
++static __u32 pxa_cerf_read32(struct map_info *map, unsigned long ofs)
++{
++ return *(__u32 *)(map->map_priv_1 + ofs);
++}
++
++static void pxa_cerf_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 pxa_cerf_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ *(__u8 *)(map->map_priv_1 + adr) = d;
++}
++
++static void pxa_cerf_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ *(__u16 *)(map->map_priv_1 + adr) = d;
++}
++
++static void pxa_cerf_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ *(__u32 *)(map->map_priv_1 + adr) = d;
++}
++
++static void pxa_cerf_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 pxa_cerf_map = {
++ name: "PXA Cerf Flash",
++ size: WINDOW_SIZE,
++ buswidth: BUSWIDTH,
++ read8: pxa_cerf_read8,
++ read16: pxa_cerf_read16,
++ read32: pxa_cerf_read32,
++ copy_from: pxa_cerf_copy_from,
++ write8: pxa_cerf_write8,
++ write16: pxa_cerf_write16,
++ write32: pxa_cerf_write32,
++ copy_to: pxa_cerf_copy_to
++};
++
++static struct mtd_partition pxa_cerf_partitions[] = {
++ {
++ name: "Bootloader",
++ size: 0x00040000,
++ offset: 0,
++ mask_flags: MTD_WRITEABLE /* force read-only */
++ },{
++ name: "Partition Tables",
++ size: 0x00080000,
++ offset: 0x00040000,
++ },{
++ name: "Kernel",
++ size: 0x00100000,
++ offset: 0x000C0000,
++ },{
++ name: "Filesystem",
++ size: WINDOW_SIZE-0x001C0000, //MTDPART_SIZ_FULL,
++ offset: 0x001C0000
++ }
++};
++
++#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_pxa_cerf(void)
++{
++ struct mtd_partition *parts;
++ int nb_parts = 0;
++ int parsed_nr_parts = 0;
++ char *part_type = "static";
++
++ printk("Probing PXA Cerf flash at physical address 0x%08x\n", WINDOW_ADDR);
++ pxa_cerf_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0);
++ if (!pxa_cerf_map.map_priv_1) {
++ printk("Failed to ioremap\n");
++ return -EIO;
++ }
++ mymtd = do_map_probe("cfi_probe", &pxa_cerf_map);
++ if (!mymtd) {
++ iounmap((void *)pxa_cerf_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 = pxa_cerf_partitions;
++ nb_parts = NB_OF(pxa_cerf_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_pxa_cerf(void)
++{
++ if (mymtd) {
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
++ if (parsed_parts)
++ kfree(parsed_parts);
++ }
++ if (pxa_cerf_map.map_priv_1)
++ iounmap((void *)pxa_cerf_map.map_priv_1);
++ return;
++}
++
++module_init(init_pxa_cerf);
++module_exit(cleanup_pxa_cerf);
++
+--- /dev/null
++++ linux-2.4.27/drivers/mtd/maps/trizeps2.c
+@@ -0,0 +1,172 @@
++/*
++ * $Id:
++ *
++ * Map driver for the Trizeps-2 module.
++ *
++ * Author: Luc De Cock
++ * Copyright: (C) 2003 Teradyne DS, Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/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 16*1024*1024
++
++static __u8 trizeps2_read8(struct map_info *map, unsigned long ofs)
++{
++ return *(__u8 *)(map->map_priv_1 + ofs);
++}
++
++static __u16 trizeps2_read16(struct map_info *map, unsigned long ofs)
++{
++ return *(__u16 *)(map->map_priv_1 + ofs);
++}
++
++static __u32 trizeps2_read32(struct map_info *map, unsigned long ofs)
++{
++ return *(__u32 *)(map->map_priv_1 + ofs);
++}
++
++static void trizeps2_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 trizeps2_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ *(__u8 *)(map->map_priv_1 + adr) = d;
++}
++
++static void trizeps2_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ *(__u16 *)(map->map_priv_1 + adr) = d;
++}
++
++static void trizeps2_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ *(__u32 *)(map->map_priv_1 + adr) = d;
++}
++
++static void trizeps2_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 trizeps2_map = {
++ name: "Trizeps-2 flash",
++ size: WINDOW_SIZE,
++ read8: trizeps2_read8,
++ read16: trizeps2_read16,
++ read32: trizeps2_read32,
++ copy_from: trizeps2_copy_from,
++ write8: trizeps2_write8,
++ write16: trizeps2_write16,
++ write32: trizeps2_write32,
++ copy_to: trizeps2_copy_to
++};
++
++static struct mtd_partition trizeps2_partitions[] = {
++ {
++ name: "Bootloader",
++ size: 0x00040000,
++ offset: 0,
++ mask_flags: MTD_WRITEABLE /* force read-only */
++ },{
++ name: "Bootloader (backup)",
++ size: 0x00040000,
++ offset: 0x00040000,
++ mask_flags: MTD_WRITEABLE /* force read-only */
++ },{
++ name: "Kernel",
++ size: 0x000C0000,
++ offset: 0x00080000,
++ },{
++ 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_trizeps2(void)
++{
++ struct mtd_partition *parts;
++ int nb_parts = 0;
++ int parsed_nr_parts = 0;
++ char *part_type = "static";
++
++ trizeps2_map.buswidth = (BOOT_DEF & 1) ? 2 : 4;
++ printk( "Probing Trizeps-2 flash at physical address 0x%08x (%d-bit buswidth)\n",
++ WINDOW_ADDR, trizeps2_map.buswidth * 8 );
++ trizeps2_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0);
++ if (!trizeps2_map.map_priv_1) {
++ printk("Failed to ioremap\n");
++ return -EIO;
++ }
++ mymtd = do_map_probe("cfi_probe", &trizeps2_map);
++ if (!mymtd) {
++ iounmap((void *)trizeps2_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 = trizeps2_partitions;
++ nb_parts = NB_OF(trizeps2_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_trizeps2(void)
++{
++ if (mymtd) {
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
++ if (parsed_parts)
++ kfree(parsed_parts);
++ }
++ if (trizeps2_map.map_priv_1)
++ iounmap((void *)trizeps2_map.map_priv_1);
++ return 0;
++}
++
++module_init(init_trizeps2);
++module_exit(cleanup_trizeps2);
++
+--- linux-2.4.27/drivers/net/Config.in~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/net/Config.in
+@@ -125,6 +125,7 @@
+ dep_tristate ' SMC Ultra support' CONFIG_ULTRA $CONFIG_ISA
+ dep_tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32 $CONFIG_EISA
+ dep_tristate ' SMC 9194 support' CONFIG_SMC9194 $CONFIG_ISA
++ tristate ' SMC 91C9x/91C1xx support' CONFIG_SMC91X
+ fi
+ bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
+ if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
+--- linux-2.4.27/drivers/net/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/net/Makefile
+@@ -137,6 +137,7 @@
+ obj-$(CONFIG_SK_G16) += sk_g16.o
+ obj-$(CONFIG_HP100) += hp100.o
+ obj-$(CONFIG_SMC9194) += smc9194.o
++obj-$(CONFIG_SMC91X) += smc91x.o
+ obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o
+ obj-$(CONFIG_ARM_ETHERH) += 8390.o
+ obj-$(CONFIG_WD80x3) += wd.o 8390.o
+--- linux-2.4.27/drivers/net/cirrus.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/net/cirrus.c
+@@ -67,6 +67,9 @@
+ #elif CONFIG_ARCH_CDB89712
+ # define CIRRUS_DEFAULT_IO ETHER_BASE + 0x300
+ # define CIRRUS_DEFAULT_IRQ IRQ_EINT3
++#elif CONFIG_ARCH_CSB226
++# define CIRRUS_DEFAULT_IO 0xF8000000
++# define CIRRUS_DEFAULT_IRQ IRQ_GPIO(14)
+ #else
+ # define CIRRUS_DEFAULT_IO 0
+ # define CIRRUS_DEFAULT_IRQ 0
+--- linux-2.4.27/drivers/net/irda/Config.in~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/net/irda/Config.in
+@@ -42,5 +42,7 @@
+ if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+ dep_tristate 'SA1100 Internal IR' CONFIG_SA1100_FIR $CONFIG_IRDA $CONFIG_EXPERIMENTAL
+ fi
+-
++if [ "$CONFIG_ARCH_PXA" = "y" ]; then
++ dep_tristate 'Intel PXA2xx Internal IR' CONFIG_PXA_FIR $CONFIG_IRDA $CONFIG_EXPERIMENTAL
++fi
+ endmenu
+--- linux-2.4.27/drivers/net/irda/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/net/irda/Makefile
+@@ -16,6 +16,7 @@
+ obj-$(CONFIG_USB_IRDA) += irda-usb.o
+ obj-$(CONFIG_NSC_FIR) += nsc-ircc.o
+ obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o
++obj-$(CONFIG_PXA_FIR) += pxa_ir.o
+ obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o
+ obj-$(CONFIG_TOSHIBA_OLD) += toshoboe.o
+ obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o
+--- /dev/null
++++ linux-2.4.27/drivers/net/irda/pxa_ir.c
+@@ -0,0 +1,1545 @@
++/*
++ * linux/drivers/net/irda/pxa_ir.c
++ *
++ * Author:
++ * Alexey Lugovskoy RTSoft.
++ * lugovskoy@rtsoft.msk.ru
++ *
++ * Dmitrij Frasenyak RTSoft.
++ * sed@mipt.sw.ru
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Infra-red SIR and FIR driver for the PXA 210/250 embedded microprocessors
++ * Based on linux/drivers/net/irda/sa1100_ir.c
++ *
++ */
++
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/netdevice.h>
++#include <linux/slab.h>
++#include <linux/rtnetlink.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/delay.h>
++
++#include <linux/pm.h>
++
++#include <net/irda/irda.h>
++#include <net/irda/irmod.h>
++#include <net/irda/wrapper.h>
++#include <net/irda/irda_device.h>
++
++#include <asm/irq.h>
++#include <asm/dma.h>
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/arch/lubbock.h>
++
++
++static int rx_count = 0;
++static int tx_count = 0;
++
++/*
++ * Our netdevice. There is only ever one of these.
++ */
++
++static struct net_device *netdev;
++
++struct pxa250_irda {
++
++ unsigned char open;
++
++ int speed;
++ int newspeed;
++
++ struct sk_buff *txskb;
++ struct sk_buff *rxskb;
++
++
++ /* => FIR */
++ unsigned int fir_irq;
++ int txdma_ch;
++ int rxdma_ch;
++ dma_addr_t txbuf_dma;
++ dma_addr_t rxbuf_dma;
++ void* txbuf_dma_virt;
++ void* rxbuf_dma_virt;
++ /* <= FIR*/
++ struct net_device_stats stats;
++ struct irlap_cb *irlap;
++ struct pm_dev *pmdev;
++ struct qos_info qos;
++
++ /* => SIR */
++ iobuff_t tx_buff;
++ iobuff_t rx_buff;
++ /* <= SIR */
++};
++
++#define IS_FIR(si) ((si)->speed >= 4000000)
++
++#define HPSIR_MAX_RXLEN 2050
++#define HPSIR_MAX_TXLEN 2050
++#define TXBUFF_MAX_SIZE HPSIR_MAX_TXLEN
++#define SET_SIR_MODE STISR = STISR_RCVEIR | STISR_XMITIR | STISR_XMODE
++
++/*
++ * If you want to disable debug information
++ * please uncomment line bellow
++ */
++
++#define PXA_FIR_DUMP_ENABLE
++#undef PXA_FIR_DUMP_ENABLE
++
++
++#define PXA_FIR_DEBUG_ENABLE
++#undef PXA_FIR_DEBUG_ENABLE
++
++#define PXA_FIR_IRQ_DEBUG_ENABLE
++#undef PXA_FIR_IRQ_DEBUG_ENABLE
++
++#ifdef PXA_FIR_DEBUG_ENABLE
++#define __ECHO_IN printk(KERN_ERR "%s: enter\n",__FUNCTION__);
++#define __ECHO_OUT printk(KERN_ERR "%s: exit\n",__FUNCTION__);
++#define DBG(args...) printk(KERN_ERR __FUNCTION__"():"args);
++#else
++#define __ECHO_IN
++#define __ECHO_OUT
++#define DBG(args...)
++#endif
++
++#ifdef PXA_FIR_IRQ_DEBUG_ENABLE
++#define DBG_IRQ(args...) printk(KERN_ERR __FUNCTION__"():"args);
++#else
++#define DBG_IRQ(args...)
++#endif
++
++
++static int pxa250_irda_set_speed(struct net_device *dev,int speed);
++static void pxa250_start_rx_dma(struct net_device *dev);
++
++
++
++/**************************************************************************
++ * Misc FIR/SIR functions *
++ **************************************************************************/
++/*
++ * Allocate the receive buffer, unless it is already allocated.
++ */
++
++static int pxa250_irda_rx_alloc(struct pxa250_irda *si)
++{
++ __ECHO_IN;
++
++ if (si->rxskb)
++ return 0;
++
++ si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
++
++ if (!si->rxskb) {
++ printk(KERN_ERR "pxa250_ir: out of memory for RX SKB\n");
++ return -ENOMEM;
++ }
++
++ /*
++ * Align any IP headers that may be contained
++ * within the frame.
++ */
++ skb_reserve(si->rxskb, 1);
++
++ __ECHO_OUT;
++
++ return 0;
++}
++
++
++
++/**************************************************************************
++ * FIR *
++ **************************************************************************/
++
++
++
++
++static inline void pxa250_dma_stop(int ch)
++{
++ __ECHO_IN;
++
++ DCSR(ch) &= ~DCSR_RUN;
++
++ __ECHO_OUT;
++
++}
++
++
++static void pxa250_ficp_rx_start(void)
++{
++ ICCR0 = 0;
++ ICCR2 = 1 << 2 | 0 << 3 ;
++ ICCR0 = ICCR0_ITR ;
++ ICCR0 |= ICCR0_RIE | ICCR0_RXE ;
++}
++
++/*
++ * Change Alternative Function encoding
++ * Enable ICP unit
++ * Disabe STUART unit
++ * Enable IRQ unit clock;
++ * Configure direction of GPIO used by ICP
++ */
++
++
++static void pxa250_do_fir_GPIO_config(void)
++{
++ /*
++ * Modify GPIO 46 and 47 Alternate Function
++ */
++
++ __ECHO_IN;
++
++ /*Switch AF*/
++ set_GPIO_mode (GPIO46_ICPRXD_MD);
++ set_GPIO_mode (GPIO47_ICPTXD_MD);
++
++ if (machine_is_lubbock())
++ LUB_MISC_WR |= 1 << 4;
++
++ /*init clock*/
++ CKEN |= CKEN13_FICP;
++
++ __ECHO_OUT;
++}
++
++/*
++ * Low level hardware configuration and startup.
++ */
++
++static int pxa250_fir_irda_startup(struct pxa250_irda *si)
++{
++
++ __ECHO_IN;
++
++ /*
++ * Disable STUART
++ */
++
++ STIER &= ~IER_UUE;
++
++ /*Disable STUART FIFO */
++ STFCR = 0;
++
++ /*
++ * Do low level configuration for HW AF and clock
++ */
++ pxa250_do_fir_GPIO_config();
++
++ __ECHO_OUT;
++ return 0;
++}
++
++
++/*
++ * Aieeeeee .. we should never get here :(
++ */
++static void pxa250_irda_rxdma_irq(int ch,void *id, struct pt_regs *regs)
++{
++ struct net_device *dev=id;
++ struct pxa250_irda *si=dev->priv;
++ u_int dcsr;
++
++
++ __ECHO_IN;
++
++ /*
++ * Make sure that irq is our.
++ */
++
++ if ( ch != si->rxdma_ch )
++ /*just*/ return;
++
++ /*
++ * Check status
++ */
++ dcsr = DCSR(ch);
++
++ DBG("DCSR=%x\n",dcsr);
++
++ if (dcsr & DCSR_STOPSTATE )
++ {
++ DBG_IRQ("Chanel %d in stop state\n",ch);
++ }
++
++ if (dcsr & DCSR_BUSERR )
++ {
++ /*
++ * BUS Error we must restart reception
++ */
++
++ DBG("PXA IrDA: bus error interrupt on channel %d\n", ch);
++ DCSR(ch) |= DCSR_BUSERR;
++ }
++
++ if (dcsr & DCSR_ENDINTR )
++ {
++ DBG("PXA IrDA: Normal end of dma channel %d - packet to big\n", ch);
++ DCSR(ch) |= DCSR_ENDINTR;
++ }
++
++ /* no mater what restart rx*/
++ pxa250_start_rx_dma(dev);
++
++ return ;
++
++}
++
++
++static void pxa250_irda_txdma_irq(int ch, void *id , struct pt_regs *regs)
++{
++ struct net_device *dev=id;
++ struct pxa250_irda *si=dev->priv;
++ struct sk_buff *skb = si->txskb;
++ u_int dcsr;
++
++
++ __ECHO_IN;
++ DBG_IRQ("transmit\n");
++
++
++ /*
++ * Make sure that irq is our.
++ */
++
++ if ( ch != si->txdma_ch )
++ /*just*/ return;
++
++
++ /*
++ * Check status
++ */
++ dcsr = DCSR(ch);
++
++ DBG("DCSR=%x",dcsr);
++
++ if (dcsr & DCSR_STOPSTATE )
++ {
++ DBG("Chanel %d in stop state\n",ch);
++ }
++
++ if (dcsr & DCSR_BUSERR )
++ {
++ DBG("PXA IrDA: bus error interrupt on channel %d\n", ch);
++ DCSR(ch) |= DCSR_BUSERR;
++ si->txskb = NULL;
++ }
++
++ if (dcsr & DCSR_ENDINTR )
++ {
++ DBG("PXA IrDA: Normal end of dma channel %d\n", ch);
++ DCSR(ch) |= DCSR_ENDINTR;
++ si->txskb = NULL;
++ }
++
++ /*
++ * Account and free the packet.
++ */
++ if (skb)
++ {
++ si->stats.tx_packets ++;
++ si->stats.tx_bytes += skb->len;
++ dev_kfree_skb_irq(skb);
++ }
++
++ /*Disable transceiver and enable receiver*/
++
++ if (si->newspeed) {
++ pxa250_irda_set_speed(dev, si->newspeed);
++ si->newspeed = 0;
++ }
++
++ while (ICSR1 & ICSR1_TBY)
++ udelay(1);
++
++ ICCR0 &= ~ICCR0_TXE;
++
++
++ enable_irq(si->fir_irq);
++
++ ICCR0 |= ICCR0_RXE;
++
++ /*
++ * Make sure that the TX queue is available for sending
++ * (for retries). TX has priority over RX at all times.
++ */
++ netif_wake_queue(dev);
++
++ __ECHO_OUT;
++}
++
++
++static void pxa250_start_rx_dma(struct net_device *dev)
++{
++ struct pxa250_irda *si = dev->priv;
++ int ch=si->rxdma_ch;
++
++ if (!si->rxskb) {
++ DBG("rx buffer went missing\n");
++/* return; */
++ }
++
++ DCSR(ch)=0;
++ DCSR(ch)=DCSR_NODESC;
++ DSADR(ch) = __PREG(ICDR);
++ DTADR(ch) = si->rxbuf_dma; /* phisical address */;
++
++ /* We should never do END_IRQ. !!!*/
++ DCMD(ch) = DCMD_ENDIRQEN| DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_BURST8 | DCMD_WIDTH1 | HPSIR_MAX_RXLEN;
++
++ /*
++ * All right information will be available as soon as we set RXE flag
++ */
++
++ DCSR(ch) = DCSR_ENDINTR | DCSR_BUSERR;
++ DCSR(ch) = DCSR_RUN | DCSR_NODESC ;
++
++}
++
++
++
++
++static int pxa250_get_rx_len(struct pxa250_irda *si)
++{
++ /*
++ * DMA have to be stoped here
++ */
++
++ if ( ! (DCSR(si->rxdma_ch) & DCSR_STOPSTATE) )
++ printk("warning dma have to be stoped befor counting len\n");
++
++ return ( HPSIR_MAX_RXLEN - ( DCMD(si->rxdma_ch) & DCMD_LENGTH ) );
++
++}
++
++static void pxa250_irda_fir_error(struct net_device *dev)
++{
++ struct pxa250_irda *si = dev->priv;
++ struct sk_buff *skb = si->rxskb;
++ int len;
++ int stat,data;
++
++ __ECHO_IN;
++
++ if (!skb)
++ {
++ printk("pxa250 fir_error: SKB is NULL!\n");
++ return;
++ }
++
++ /*
++ * Get the current data position.
++ */
++
++ len=pxa250_get_rx_len(si);
++ DBG("RXLEN=%d\n",len);
++ memcpy(skb->data, si->rxbuf_dma_virt, len);
++
++ do {
++ /*
++ * Read Status, and then Data.
++ */
++ stat = ICSR1;
++ rmb();
++ data = ICDR;
++ if (stat & (ICSR1_CRE | ICSR1_ROR)) {
++ si->stats.rx_errors++;
++ if (stat & ICSR1_CRE)
++ si->stats.rx_crc_errors++;
++ if (stat & ICSR1_ROR)
++ si->stats.rx_frame_errors++;
++ } else
++ skb->data[len++] = data;
++
++ /*
++ * If we hit the end of frame, there's
++ * no point in continuing.
++ */
++ if (stat & ICSR1_EOF)
++ break;
++ } while (ICSR0 & ICSR0_EIF);
++
++ if (stat & ICSR1_EOF) {
++ si->rxskb = NULL;
++
++ skb_put(skb, len);
++ skb->dev = dev;
++ skb->mac.raw = skb->data;
++ skb->protocol = htons(ETH_P_IRDA);
++ si->stats.rx_packets++;
++ si->stats.rx_bytes += len;
++
++ /*
++ * Before we pass the buffer up, allocate a new one.
++ */
++
++ si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
++
++ if (!si->rxskb) {
++ printk(KERN_ERR "pxa250_ir: out of memory for RX SKB\n");
++ return;
++ }
++
++ /*
++ * Align any IP headers that may be contained
++ * within the frame.
++ */
++ skb_reserve(si->rxskb, 1);
++
++ netif_rx(skb);
++ }
++}
++
++/*
++ * FIR format interrupt service routine. We only have to
++ * handle RX events; transmit events go via the TX DMA irq handler.
++ *
++ * No matter what, we disable RX, process, and then restart RX.
++ */
++
++static void pxa250_irda_fir_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct net_device *dev = dev_id;
++ struct pxa250_irda *si = dev->priv;
++ int status;
++
++ /*
++ * Stop RX
++ */
++
++ __ECHO_IN;
++
++ pxa250_dma_stop(si->rxdma_ch);
++
++
++ /*
++ * Framing error - we throw away the packet completely.
++ * Clearing RXE flushes the error conditions and data
++ * from the fifo.
++ */
++ status=ICSR0;
++
++ if (status & (ICSR0_FRE | ICSR0_RAB)) {
++ DBG_IRQ("Framing error or RAB\n");
++
++ si->stats.rx_errors++;
++
++ if (ICSR0 & ICSR0_FRE)
++ si->stats.rx_frame_errors++;
++
++ /* Clear RX fifo
++ * DMA will be cleared when we restart RX
++ * Should we check RNE after that?
++ */
++
++ ICCR0 &= ~ICCR0_RXE;
++
++ /*
++ * Clear selected status bits now, so we
++ * don't miss them next time around.
++ */
++ ICSR0 = status & (ICSR0_FRE | ICSR0_RAB);
++ }
++
++
++ /*
++ * Deal with any receive errors. The any of the lowest
++ * 8 bytes in the FIFO may contain an error. We must read
++ * them one by one. The "error" could even be the end of
++ * packet!
++ */
++ if (ICSR0 & ICSR0_EIF)
++ pxa250_irda_fir_error(dev);
++
++ /*
++ * No matter what happens, we must restart reception.
++ */
++
++ ICCR0 = 0;
++ pxa250_start_rx_dma(dev);
++ pxa250_ficp_rx_start();
++ __ECHO_OUT;
++}
++
++
++
++
++
++/**************************************************************************
++ * SIR *
++ **************************************************************************/
++/*
++ * HP-SIR format interrupt service routines.
++ */
++static void pxa250_sir_transmit(struct net_device *dev)
++{
++ struct pxa250_irda *si = dev->priv;
++
++ if (si->tx_buff.len)
++ {
++ /* Disable receiver and enable transmiter*/
++
++
++
++ STISR &= ~STISR_RCVEIR;
++// STISR |= STISR_XMITIR;
++
++
++
++ disable_irq(dev->irq);
++
++ do
++ {
++
++ if (STLSR & LSR_TDRQ)
++ {
++ STTHR = *si->tx_buff.data++;
++ si->tx_buff.len -= 1;
++
++ tx_count++;
++ }
++
++
++ } while (si->tx_buff.len);
++
++
++ if (si->tx_buff.len == 0)
++ {
++
++
++ si->stats.tx_packets++;
++ si->stats.tx_bytes += si->tx_buff.data -
++ si->tx_buff.head;
++
++ /*
++ * We need to ensure that the transmitter has
++ * finished.
++ */
++
++ do
++ {
++ udelay(1);
++
++ }
++ while ( ! (STLSR & LSR_TEMT) );
++
++
++ /*
++
++ * Ok, we've finished transmitting. Now enable
++ * the receiver. Sometimes we get a receive IRQ
++ * immediately after a transmit...
++ */
++
++ if (si->newspeed)
++ {
++ pxa250_irda_set_speed(dev, si->newspeed);
++ si->newspeed = 0;
++ }
++
++ /* I'm hungry! */
++ netif_wake_queue(dev);
++ }
++
++ enable_irq (dev->irq);
++ STIER = (IER_RAVIE | IER_UUE | IER_RTIOE);
++
++ STISR |= STISR_RCVEIR;
++// STISR &= ~STISR_XMITIR;
++ }
++}
++
++static void pxa250_irda_hpsir_irq(struct net_device *dev)
++{
++ struct pxa250_irda *si = dev->priv;
++
++ /*
++ * Deal with any receive errors first. The bytes in error may be
++ * the only bytes in the receive FIFO, so we do this first.
++ */
++ __ECHO_IN;
++
++ while (STLSR & LSR_FIFOE)
++ {
++ int stat, data;
++
++ stat = STLSR;
++ data = STRBR;
++
++
++ if (stat & (LSR_FE | LSR_OE | LSR_PE))
++
++ {
++ si->stats.rx_errors++;
++ if (stat & LSR_FE)
++ si->stats.rx_frame_errors++;
++ if (stat & LSR_OE)
++ si->stats.rx_fifo_errors++;
++
++ } else
++ {
++ rx_count++;
++ async_unwrap_char(dev, &si->stats, &si->rx_buff, data);
++ }
++
++ }
++
++ /*
++ * We must clear certain bits.
++ */
++
++ if (STLSR & (LSR_DR))
++ {
++ /*
++ * Fifo contains at least 1 character.
++ */
++ do
++ {
++ int data;
++
++ data = STRBR;
++
++ async_unwrap_char(dev, &si->stats, &si->rx_buff,
++ data); /* was Ser2UTDR); Clo */
++ rx_count++;
++
++ } while (STLSR & LSR_DR);
++
++ dev->last_rx = jiffies;
++ }
++
++ __ECHO_OUT;
++}
++
++static void pxa250_sir_irda_shutdown(struct pxa250_irda *si)
++{
++
++ STIER = 0;
++ STFCR = 0;
++ STISR = 0;
++ CKEN &= ~CKEN5_STUART;
++}
++
++
++/************************************************************************************/
++
++/*Low level init/uninstall function PM control and IrDA protocol stack registration */
++
++/*
++ * Set the IrDA communications speed.
++ * Interrupt have to be disabled here.
++ */
++
++static int pxa250_irda_startup(struct net_device *dev)
++{
++
++
++ __ECHO_IN;
++
++ /*
++ * Ensure that the ports for this device are setup correctly.
++ */
++
++
++ set_GPIO_mode (GPIO46_STRXD_MD);
++ set_GPIO_mode (GPIO47_STTXD_MD);
++
++ STMCR = MCR_OUT2;
++ STLCR = LCR_WLS1 | LCR_WLS0;
++
++ SET_SIR_MODE;
++ CKEN |= CKEN5_STUART;
++ /* enable irq from stuart */
++ ICMR |= ( 1 << 20 );
++
++ /*reset FIFO*/
++
++/* STFCR = FCR_TRFIFOE | FCR_RESETTF | FCR_RESETRF;// | FCR_ITL_16;
++
++ STIER = IER_UUE | IER_RAVIE | IER_RTOIE;
++*/
++ __ECHO_OUT;
++
++ return 0;
++
++}
++
++
++#ifdef CONFIG_PM
++/*
++ * Suspend the IrDA interface.
++ */
++
++static int pxa250_irda_shutdown(struct pxa250_irda *si)
++{
++
++ pxa250_sir_irda_shutdown(si);
++ return 0;
++
++}
++
++
++static int pxa250_irda_suspend(struct net_device *dev, int state)
++{
++ struct pxa250_irda *si = dev->priv;
++
++ if (si && si->open) {
++ /*
++ * Stop the transmit queue
++ */
++ if (IS_FIR(si))
++ return -1;
++
++ netif_stop_queue(dev);
++ disable_irq(dev->irq);
++ disable_irq(si->fir_irq);
++ pxa250_sir_irda_shutdown(si);
++ }
++
++ return 0;
++}
++
++/*
++ * Resume the IrDA interface.
++ */
++
++static int pxa250_irda_resume(struct net_device *dev)
++{
++ struct pxa250_irda *si = dev->priv;
++
++ __ECHO_IN;
++
++ if (si && si->open) {
++ /*
++ * If we missed a speed change, initialise at the new speed
++ * directly. It is debatable whether this is actually
++ * required, but in the interests of continuing from where
++ * we left off it is desireable. The converse argument is
++ * that we should re-negotiate at 9600 baud again.
++ */
++ if (si->newspeed) {
++ si->speed = si->newspeed;
++ si->newspeed = 0;
++ }
++
++ pxa250_irda_startup(dev);
++ enable_irq(dev->irq);
++
++ /*
++ * This automatically wakes up the queue
++ */
++ netif_wake_queue(dev);
++ pxa250_irda_set_speed(dev,si->speed = 9600);
++
++ }
++
++ __ECHO_OUT;
++ return 0;
++}
++
++static int pxa250_irda_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
++{
++ int ret;
++
++
++ if (!dev->data)
++ return -EINVAL;
++
++
++ switch (rqst) {
++ case PM_SUSPEND:
++ ret = pxa250_irda_suspend((struct net_device *)dev->data,
++ (int)data);
++ break;
++
++ case PM_RESUME:
++ ret = pxa250_irda_resume((struct net_device *)dev->data);
++ break;
++
++ default:
++
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret;
++}
++#endif
++
++
++
++
++static void pxa250_irda_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct net_device *dev = dev_id;
++
++ pxa250_irda_hpsir_irq(dev);
++
++}
++
++
++static int pxa250_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct pxa250_irda *si = dev->priv;
++ int speed = irda_get_next_speed(skb);
++ int mtt;
++
++ __ECHO_IN;
++
++ /*
++ * Does this packet contain a request to change the interface
++ * speed? If so, remember it until we complete the transmission
++ * of this frame.
++ */
++ if (speed != si->speed && speed != -1)
++ si->newspeed = speed;
++
++ /*
++ * If this is an empty frame, we can bypass a lot.
++ */
++ if (skb->len == 0) {
++ if (si->newspeed) {
++ si->newspeed = 0;
++ pxa250_irda_set_speed(dev, speed);
++ }
++ dev_kfree_skb(skb);
++ return 0;
++ }
++
++
++ DBG("stop queue\n");
++ netif_stop_queue(dev);
++
++ if(!IS_FIR(si))
++ {
++
++ si->tx_buff.data = si->tx_buff.head;
++ si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data,
++ si->tx_buff.truesize);
++
++
++ pxa250_sir_transmit(dev);
++
++
++
++ dev_kfree_skb(skb);
++
++ dev->trans_start = jiffies;
++
++ return 0;
++ }
++ else /* FIR */
++ {
++ DBG("Enter FIR transmit\n");
++ /*
++ * We must not be transmitting...
++ */
++ if (si->txskb)
++ BUG();
++
++ disable_irq(si->fir_irq);
++
++ netif_stop_queue(dev);
++ DBG("queue stoped\n");
++ si->txskb = skb;
++
++ /* we could not just map so we'll need some triks */
++ /* skb->data may be not DMA capable -Sed- */
++
++
++ if (skb->len > TXBUFF_MAX_SIZE)
++ {
++ printk (KERN_ERR "skb data too large\n");
++ printk (KERN_ERR "len=%d",skb->len);
++ BUG();
++ }
++
++
++ DBG("gonna copy %d bytes to txbuf\n",skb->len);
++
++ memcpy (si->txbuf_dma_virt, skb->data , skb->len);
++
++ /* Actual sending ;must not be receiving !!! */
++ /* Write data and source address */
++
++ DBG("ICSR1 & RNE =%d\n",(ICSR1 & ICSR1_RNE) ? 1 : 0 );
++
++ /*Disable receiver and enable transifer */
++ ICCR0 &= ~ICCR0_RXE;
++
++ if (ICSR1 & ICSR1_TBY)
++ BUG();
++
++ ICCR0 |= ICCR0_TXE;
++
++ DBG("FICP status %x\n",ICSR0);
++
++ if (0){
++ int i;
++
++ DBG("sending packet\n");
++ for (i=0;i<skb->len;i++)
++ (i % 64) ? printk ("%2x ",skb->data[i]) : printk ("%2x \n",skb->data[i]) ;
++ DBG(" done\n");
++
++ }
++ /*
++ * If we have a mean turn-around time, impose the specified
++ * specified delay. We could shorten this by timing from
++ * the point we received the packet.
++ */
++
++ mtt = irda_get_mtt(skb);
++ if(mtt)
++ udelay(mtt);
++
++ DCSR(si->txdma_ch)=0;
++ DCSR(si->txdma_ch)=DCSR_NODESC;
++ DSADR(si->txdma_ch) = si->txbuf_dma; /* phisic address */
++ DTADR(si->txdma_ch) = __PREG(ICDR);
++
++ DCMD(si->txdma_ch) = DCMD_ENDIRQEN| DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_BURST8 | DCMD_WIDTH1 | skb->len;
++
++ DCSR(si->txdma_ch) = DCSR_ENDINTR | DCSR_BUSERR;
++ DCSR(si->txdma_ch) = DCSR_RUN | DCSR_NODESC ;
++
++ DBG("FICP status %x\n",ICSR0);
++
++ return 0;
++ }
++
++}
++
++static int
++pxa250_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
++{
++ struct if_irda_req *rq = (struct if_irda_req *)ifreq;
++ struct pxa250_irda *si = dev->priv;
++ int ret = -EOPNOTSUPP;
++
++ __ECHO_IN;
++
++ switch (cmd) {
++ case SIOCSBANDWIDTH:
++ if (capable(CAP_NET_ADMIN)) {
++ /*
++ * We are unable to set the speed if the
++ * device is not running.
++ */
++ if (si->open) {
++ ret = pxa250_irda_set_speed(dev,
++ rq->ifr_baudrate);
++ } else {
++ printk("pxa250_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n");
++ ret = 0;
++ }
++ }
++ break;
++
++ case SIOCSMEDIABUSY:
++ ret = -EPERM;
++ if (capable(CAP_NET_ADMIN)) {
++ irda_device_set_media_busy(dev, TRUE);
++ ret = 0;
++ }
++ break;
++
++ case SIOCGRECEIVING:
++ rq->ifr_receiving = IS_FIR(si) ? 0
++ : si->rx_buff.state != OUTSIDE_FRAME;
++ break;
++
++ default:
++ break;
++ }
++
++ __ECHO_OUT;
++
++ return ret;
++}
++
++static struct net_device_stats *pxa250_irda_stats(struct net_device *dev)
++{
++ struct pxa250_irda *si = dev->priv;
++ return &si->stats;
++}
++
++static int pxa250_irda_start(struct net_device *dev)
++{
++ struct pxa250_irda *si = dev->priv;
++ int err;
++ unsigned int flags;
++
++
++ MOD_INC_USE_COUNT;
++
++ __ECHO_IN;
++ si->speed = 9600;
++
++ local_irq_save(flags);
++
++ err = request_irq(si->fir_irq, pxa250_irda_fir_irq, 0, dev->name, dev);
++ if (err)
++ goto err_fir_irq;
++
++ err = request_irq(dev->irq, pxa250_irda_irq, 0, dev->name, dev);
++ if (err)
++ goto err_irq;
++
++ /*
++ * The interrupt must remain disabled for now.
++ */
++
++ disable_irq(dev->irq);
++ disable_irq(si->fir_irq);
++
++ local_irq_restore(flags);
++
++
++ /* Allocate DMA channel for receiver (not used) */
++ err = pxa_request_dma("IrDA receive", DMA_PRIO_LOW, pxa250_irda_rxdma_irq, dev);
++ if (err < 0 )
++ goto err_rx_dma;
++ si->rxdma_ch=err;
++
++ DRCMRRXICDR = DRCMR_MAPVLD | si->rxdma_ch;
++
++
++ /* Allocate DMA channel for transmit */
++ err = pxa_request_dma("IrDA transmit", DMA_PRIO_LOW, pxa250_irda_txdma_irq , dev);
++ if (err < 0 )
++ goto err_tx_dma;
++
++ si->txdma_ch=err;
++
++ /*
++ * Make sure that ICP will be able
++ * to assert the transmit dma request bit
++ * through the peripherals request bus (PREQ)
++ */
++
++ DRCMRTXICDR = DRCMR_MAPVLD | si->txdma_ch;
++
++ DBG("rx(not used) channel=%d tx channel=%d\n",si->rxdma_ch,si->txdma_ch);
++
++ /* allocate consistent buffers for dma access
++ * buffers have to be aligned and situated in dma capable memory region;
++ */
++ si->rxbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA ,HPSIR_MAX_RXLEN , &si->rxbuf_dma);
++ if (! si->rxbuf_dma_virt )
++ goto err_rxbuf_dma;
++
++ si->txbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA, HPSIR_MAX_TXLEN, &si->txbuf_dma);
++ if (! si->txbuf_dma_virt )
++ goto err_txbuf_dma;
++
++ /* Alocate skb for receiver */
++ err=pxa250_irda_rx_alloc(si);
++ if (err)
++ goto err_rx_alloc;
++
++ /*
++ * Setup the serial port for the specified config.
++ */
++ err = pxa250_irda_startup(dev);
++ if (err)
++ goto err_startup;
++
++ pxa250_irda_set_speed(dev,si->speed = 9600);
++
++
++ /*
++ * Open a new IrLAP layer instance.
++ */
++ si->irlap = irlap_open(dev, &si->qos, "pxa250");
++ err = -ENOMEM;
++ if (!si->irlap)
++ goto err_irlap;
++
++ /*
++ * Now enable the interrupt and start the queue
++ */
++ si->open = 1;
++ enable_irq(dev->irq);
++ netif_start_queue(dev);
++ return 0;
++
++err_irlap:
++ si->open = 0;
++ pxa250_sir_irda_shutdown(si);
++err_startup:
++ dev_kfree_skb(si->rxskb);
++err_rx_alloc:
++ consistent_free (si->txbuf_dma_virt,HPSIR_MAX_TXLEN,si->txbuf_dma);
++err_txbuf_dma:
++ consistent_free (si->rxbuf_dma_virt,HPSIR_MAX_RXLEN,si->rxbuf_dma);
++err_rxbuf_dma:
++ pxa_free_dma(si->txdma_ch);
++err_tx_dma:
++ pxa_free_dma(si->rxdma_ch);
++err_rx_dma:
++ free_irq(dev->irq, dev);
++err_irq:
++ free_irq(si->fir_irq, dev);
++err_fir_irq:
++ MOD_DEC_USE_COUNT;
++ return err;
++}
++
++static int pxa250_irda_stop(struct net_device *dev)
++{
++ struct pxa250_irda *si = dev->priv;
++
++ printk(KERN_ERR "Irda stop... RX = %d TX = %d\n",rx_count,tx_count);
++
++ disable_irq(dev->irq);
++ disable_irq(si->fir_irq);
++/* pxa250_irda_shutdown(si); */
++
++ /*
++ * If we have been doing DMA receive, make sure we
++ * tidy that up cleanly.
++ */
++ if (si->rxskb) {
++ dev_kfree_skb(si->rxskb);
++ si->rxskb = NULL;
++ }
++
++ /* Stop IrLAP */
++ if (si->irlap) {
++ irlap_close(si->irlap);
++ si->irlap = NULL;
++ }
++
++ consistent_free (si->txbuf_dma_virt,HPSIR_MAX_TXLEN,si->txbuf_dma);
++ consistent_free (si->rxbuf_dma_virt,HPSIR_MAX_RXLEN,si->rxbuf_dma);
++ pxa_free_dma(si->txdma_ch);
++ pxa_free_dma(si->rxdma_ch);
++
++ netif_stop_queue(dev);
++ si->open = 0;
++
++ /*
++ * Free resources
++ */
++ free_irq(dev->irq, dev);
++ free_irq(si->fir_irq, dev);
++
++
++ MOD_DEC_USE_COUNT;
++
++ return 0;
++}
++
++static int pxa250_irda_init_iobuf(iobuff_t *io, int size)
++{
++ io->head = kmalloc(size, GFP_KERNEL | GFP_DMA);
++ if (io->head != NULL) {
++ io->truesize = size;
++ io->in_frame = FALSE;
++ io->state = OUTSIDE_FRAME;
++ io->data = io->head;
++ }
++ return io->head ? 0 : -ENOMEM;
++}
++
++
++
++
++static int pxa250_stop_fir(struct net_device *dev)
++{
++ struct pxa250_irda *si = dev->priv;
++ unsigned int flag;
++
++ save_flags(flag);
++ cli();
++
++ pxa250_dma_stop(si->txdma_ch);
++ pxa250_dma_stop(si->rxdma_ch);
++
++ if (si->txskb)
++ dev_kfree_skb_irq(si->txskb);
++
++ ICCR0 &= ~(ICCR0_RXE | ICCR0_TXE );
++ disable_irq(si->fir_irq);
++ CKEN &= ~CKEN13_FICP;
++
++ restore_flags(flag);
++
++ return 0;
++}
++
++
++
++static int pxa250_irda_set_speed(struct net_device *dev, int speed)
++{
++ struct pxa250_irda *si = dev->priv;
++ int brd, ret = -EINVAL;
++ static int last_fir_speed=0;
++
++ __ECHO_IN;
++
++
++
++ switch (speed) {
++ case 9600: case 19200: case 38400:
++ case 57600: case 115200:
++
++ /* Baud rate fixed - Clo */
++
++ /*
++ * FIXME
++ */
++ if (last_fir_speed)
++ {
++
++ pxa250_stop_fir(dev);
++ set_GPIO_mode (GPIO46_STRXD_MD);
++ set_GPIO_mode (GPIO47_STTXD_MD);
++
++ enable_irq(dev->irq);
++ netif_wake_queue(dev);
++ last_fir_speed=0;
++ }
++
++
++ LUB_MISC_WR &= ~(1 << 4);
++
++ brd = 14745600 / (16 * speed);
++
++ STLCR |= LCR_DLAB;
++
++ STDLH = brd >> 8; /* Clo: set Divisor Latch High */
++ STDLL = brd & 0xFF; /* Clo: set Devisor Latch Low */
++
++ STLCR &= ~LCR_DLAB; /* Clo: clear DLAB bit */
++
++ STMCR = MCR_OUT2;
++
++ CKEN |= CKEN5_STUART;
++
++ ICMR |= ( 1 << 20 );
++
++ STLCR = LCR_WLS1 | LCR_WLS0;
++
++ SET_SIR_MODE;
++
++ STFCR = FCR_TRFIFOE | FCR_RESETTF | FCR_RESETRF | FCR_ITL_1 ;// | FCR_ITL_16;
++
++ STIER = IER_UUE | IER_RAVIE | IER_RTIOE;
++
++ si->speed = speed;
++
++ ret = 0;
++ break;
++
++ case 4000000:
++
++ if (last_fir_speed)
++ goto speed_out;
++
++ disable_irq(dev->irq);
++
++ pxa250_sir_irda_shutdown(si);
++ pxa250_fir_irda_startup(si);
++ pxa250_irda_rx_alloc(si);
++ ICCR0=0;
++ pxa250_start_rx_dma(dev);
++ pxa250_ficp_rx_start();
++
++ enable_irq(si->fir_irq);
++ DBG("enable FIR \n");
++ si->speed = speed;
++
++ netif_wake_queue(dev);
++ last_fir_speed=1;
++speed_out:
++
++ ret=0;
++
++ break;
++
++ default:
++ break;
++ }
++ __ECHO_OUT;
++
++ return ret;
++}
++
++
++static int pxa250_irda_net_init(struct net_device *dev)
++{
++ struct pxa250_irda *si = dev->priv;
++ unsigned int baudrate_mask;
++ int err = -ENOMEM;
++
++ si = kmalloc(sizeof(struct pxa250_irda), GFP_KERNEL);
++ if (!si)
++ goto out;
++
++ memset(si, 0, sizeof(*si));
++
++ /*
++ * Initialise the HP-SIR buffers
++ */
++
++ err = pxa250_irda_init_iobuf(&si->rx_buff, 14384);
++ if (err)
++ goto out;
++ err = pxa250_irda_init_iobuf(&si->tx_buff, 4000);
++ if (err)
++ goto out_free_rx;
++
++ si->fir_irq = IRQ_ICP;
++ dev->priv = si;
++ dev->hard_start_xmit = pxa250_irda_hard_xmit;
++ dev->open = pxa250_irda_start;
++ dev->stop = pxa250_irda_stop;
++ dev->do_ioctl = pxa250_irda_ioctl;
++ dev->get_stats = pxa250_irda_stats;
++
++ irda_device_setup(dev);
++ irda_init_max_qos_capabilies(&si->qos);
++
++ /*
++ * We support original IRDA up to 115k2. (we don't currently
++ * support 4Mbps). Min Turn Time set to 1ms or greater.
++ */
++ baudrate_mask = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
++ baudrate_mask |= IR_4000000 << 8;
++ si->qos.baud_rate.bits &= baudrate_mask;
++ si->qos.min_turn_time.bits = 7;
++
++ irda_qos_bits_to_value(&si->qos);
++
++#ifdef CONFIG_PM
++ /*
++ * Power-Management is optional.
++ */
++ si->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, pxa250_irda_pmproc);
++ if (si->pmdev)
++ si->pmdev->data = dev;
++#endif
++
++ return 0;
++
++ kfree(si->tx_buff.head);
++out_free_rx:
++ kfree(si->rx_buff.head);
++out:
++ kfree(si);
++
++ return err;
++}
++
++/*
++ * Remove all traces of this driver module from the kernel, so we can't be
++ * called. Note that the device has already been stopped, so we don't have
++ * to worry about interrupts or dma.
++ */
++static void pxa250_irda_net_uninit(struct net_device *dev)
++{
++ struct pxa250_irda *si = dev->priv;
++
++ dev->hard_start_xmit = NULL;
++ dev->open = NULL;
++ dev->stop = NULL;
++ dev->do_ioctl = NULL;
++ dev->get_stats = NULL;
++ dev->priv = NULL;
++
++ pm_unregister(si->pmdev);
++
++ kfree(si->tx_buff.head);
++ kfree(si->rx_buff.head);
++ kfree(si);
++}
++
++static int __init pxa250_irda_init(void)
++{
++ struct net_device *dev;
++ int err;
++
++ /* STUART */
++ err = request_mem_region(__PREG(STRBR), 0x24, "IrDA") ? 0 : -EBUSY;
++ if (err)
++ goto err_mem_1;
++
++ /* FIR */
++ err = request_mem_region(__PREG(ICCR0), 0x1c, "IrDA") ? 0 : -EBUSY;
++ if (err)
++ goto err_mem_2;
++
++
++ rtnl_lock();
++ dev = dev_alloc("irda%d", &err);
++ if (dev) {
++ dev->irq = IRQ_STUART;
++ dev->init = pxa250_irda_net_init;
++ dev->uninit = pxa250_irda_net_uninit;
++
++ err = register_netdevice(dev);
++
++ if (err)
++ kfree(dev);
++ else
++ netdev = dev;
++ }
++ rtnl_unlock();
++
++ if (err) {
++ release_mem_region(__PREG(ICCR0), 0x1c);
++err_mem_2:
++ release_mem_region(__PREG(STRBR), 0x24);
++ }
++err_mem_1:
++ return err;
++}
++
++static void __exit pxa250_irda_exit(void)
++{
++ struct net_device *dev = netdev;
++
++ netdev = NULL;
++ if (dev) {
++ rtnl_lock();
++ unregister_netdevice(dev);
++ rtnl_unlock();
++ }
++
++ release_mem_region(__PREG(ICCR0), 0x1c);
++
++ release_mem_region(__PREG(STRBR), 0x24);
++
++ /*
++ * We now know that the netdevice is no longer in use, and all
++ * references to our driver have been removed. The only structure
++ * which may still be present is the netdevice, which will get
++ * cleaned up by net/core/dev.c
++ */
++}
++
++module_init(pxa250_irda_init);
++module_exit(pxa250_irda_exit);
++
++MODULE_AUTHOR("Alexey Lugovskoy Frasenyak Dmitrij");
++MODULE_DESCRIPTION("PXA250 SIR/FIR");
++MODULE_LICENSE("GPL");
++EXPORT_NO_SYMBOLS;
+--- /dev/null
++++ linux-2.4.27/drivers/net/smc91x.c
+@@ -0,0 +1,2123 @@
++/*------------------------------------------------------------------------
++ . smc91x.c
++ . This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices.
++ .
++ . Copyright (C) 1996 by Erik Stahlman
++ . Copyright (C) 2001 Standard Microsystems Corporation
++ . Developed by Simple Network Magic Corporation
++ . Copyright (C) 2003 Monta Vista Software, Inc.
++ . Unified SMC91x driver by Nicolas Pitre
++ .
++ . This program is free software; you can redistribute it and/or modify
++ . it under the terms of the GNU General Public License as published by
++ . the Free Software Foundation; either version 2 of the License, or
++ . (at your option) any later version.
++ .
++ . This program is distributed in the hope that it will be useful,
++ . but WITHOUT ANY WARRANTY; without even the implied warranty of
++ . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ . GNU General Public License for more details.
++ .
++ . You should have received a copy of the GNU General Public License
++ . along with this program; if not, write to the Free Software
++ . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ .
++ . Arguments:
++ . io = for the base address
++ . irq = for the IRQ
++ . nowait = 0 for normal wait states, 1 eliminates additional wait states
++ .
++ . original author:
++ . Erik Stahlman <erik@vt.edu>
++ .
++ . hardware multicast code:
++ . Peter Cammaert <pc@denkart.be>
++ .
++ . contributors:
++ . Daris A Nevil <dnevil@snmc.com>
++ . Nicolas Pitre <nico@cam.org>
++ .
++ . History:
++ . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet
++ . 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ"
++ . 03/16/01 Daris A Nevil modified smc9194.c for use with LAN91C111
++ . 08/22/01 Scott Anderson merge changes from smc9194 to smc91111
++ . 08/21/01 Pramod B Bhardwaj added support for RevB of LAN91C111
++ . 12/20/01 Jeff Sutherland initial port to Xscale PXA with DMA support
++ . 04/07/03 Nicolas Pitre unified SMC91x driver, killed irq races,
++ . more bus abstraction, big cleanup, etc.
++ ----------------------------------------------------------------------------*/
++
++static const char version[] =
++ "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre <nico@cam.org>\n";
++
++/* Debugging level */
++#ifndef SMC_DEBUG
++#define SMC_DEBUG 0
++#endif
++
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#ifdef CONFIG_PM
++#include <linux/pm.h>
++#endif
++
++#include <asm/io.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include "smc91x.h"
++
++
++#ifdef CONFIG_ISA
++/*
++ . the LAN91C111 can be at any of the following port addresses. To change,
++ . for a slightly different card, you can add it to the array. Keep in
++ . mind that the array must end in zero.
++*/
++static unsigned int smc_portlist[] __initdata = {
++ 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
++ 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0
++};
++#endif /* CONFIG_ISA */
++
++#ifndef SMC_IOADDR
++# define SMC_IOADDR -1
++#endif
++static int io = SMC_IOADDR;
++
++#ifndef SMC_IRQ
++# define SMC_IRQ -1
++#endif
++static int irq = SMC_IRQ;
++
++#ifndef SMC_NOWAIT
++# define SMC_NOWAIT 0
++#endif
++static int nowait = SMC_NOWAIT;
++
++MODULE_PARM(io, "i");
++MODULE_PARM(irq, "i");
++MODULE_PARM(nowait, "i");
++MODULE_PARM_DESC(io, "I/O base address");
++MODULE_PARM_DESC(irq, "IRQ number");
++MODULE_PARM_DESC(nowait, "set to 1 for no wait state");
++
++
++/*------------------------------------------------------------------------
++ .
++ . The internal workings of the driver. If you are changing anything
++ . here with the SMC stuff, you should have the datasheet and know
++ . what you are doing.
++ .
++ -------------------------------------------------------------------------*/
++#define CARDNAME "LAN91x"
++
++// Use power-down feature of the chip
++#define POWER_DOWN 1
++
++/*
++ . Wait time for memory to be free. This probably shouldn't be
++ . tuned that much, as waiting for this means nothing else happens
++ . in the system
++*/
++#define MEMORY_WAIT_TIME 16
++
++/*
++ . This selects whether TX packets are sent one by one to the SMC91x internal
++ . memory ans throttled until transmission completes. This may prevent
++ . RX overruns a litle by keeping much of the memory free for RX packets
++ . but to the expense of reduced TX throughput and increased IRQ overhead.
++ . Note this is not a cure for a too slow data bus or too high IRQ latency.
++ */
++#define THROTTLE_TX_PKTS 0
++
++
++/* store this information for the driver.. */
++struct smc_local {
++
++ // If I have to wait until memory is available to send
++ // a packet, I will store the skbuff here, until I get the
++ // desired memory. Then, I'll send it out and free it.
++ struct sk_buff *saved_skb;
++
++ // these are things that the kernel wants me to keep, so users
++ // can find out semi-useless statistics of how well the card is
++ // performing
++ struct net_device_stats stats;
++
++ // version/revision of the SMC91x chip
++ int version;
++
++ // Set to true during the auto-negotiation sequence
++ int autoneg_active;
++
++ // Address of our PHY port
++ int phyaddr;
++
++ // Type of PHY
++ int phytype;
++
++ // Last contents of PHY Register 18
++ int lastPhy18;
++
++ // Contains the current active transmission mode
++ int tcr_cur_mode;
++
++ // Contains the current active receive mode
++ int rcr_cur_mode;
++
++ // Contains the current active receive/phy mode
++ int rpc_cur_mode;
++ int ctl_autoneg;
++ int ctl_rfduplx;
++ int ctl_rspeed;
++
++#ifdef CONFIG_PM
++ struct pm_dev* pm;
++#endif
++
++};
++
++
++#if SMC_DEBUG > 2
++#define PRINTK3(args...) printk(args)
++#else
++#define PRINTK3(args...) do { } while(0)
++#endif
++
++#if SMC_DEBUG > 1
++#define PRINTK2(args...) printk(args)
++#else
++#define PRINTK2(args...) do { } while(0)
++#endif
++
++#if SMC_DEBUG > 0
++#define PRINTK1(args...) printk(args)
++#define PRINTK(args...) printk(args)
++#else
++#define PRINTK1(args...) do { } while(0)
++#define PRINTK(args...) printk(KERN_DEBUG args)
++#endif
++
++#if SMC_DEBUG > 3
++static void PRINT_PKT(u_char *buf, int length)
++{
++ int i;
++ int remainder;
++ int lines;
++
++ lines = length / 16;
++ remainder = length % 16;
++
++ for (i = 0; i < lines ; i ++) {
++ int cur;
++ for (cur = 0; cur < 8; cur++) {
++ u_char a, b;
++ a = *buf++;
++ b = *buf++;
++ printk("%02x%02x ", a, b);
++ }
++ printk("\n");
++ }
++ for (i = 0; i < remainder/2 ; i++) {
++ u_char a, b;
++ a = *buf++;
++ b = *buf++;
++ printk("%02x%02x ", a, b );
++ }
++ printk("\n");
++}
++#else
++#define PRINT_PKT(x...) do { } while(0)
++#endif
++
++
++/* this enables an interrupt in the interrupt mask register */
++#define SMC_ENABLE_INT(x) do { \
++ unsigned long flags; \
++ unsigned char mask; \
++ local_irq_save(flags); \
++ mask = SMC_GET_INT_MASK(); \
++ mask |= (x); \
++ SMC_SET_INT_MASK(mask); \
++ local_irq_restore(flags); \
++} while (0)
++
++/* this disables an interrupt from the interrupt mask register */
++#define SMC_DISABLE_INT(x) do { \
++ unsigned long flags; \
++ unsigned char mask; \
++ local_irq_save(flags); \
++ mask = SMC_GET_INT_MASK(); \
++ mask &= ~(x); \
++ SMC_SET_INT_MASK(mask); \
++ local_irq_restore(flags); \
++} while (0)
++
++/* wait while MMU is busy */
++#define SMC_WAIT_MMU_BUSY() do { \
++ if (unlikely(SMC_GET_MMU_CMD() & MC_BUSY)) { \
++ unsigned long timeout = jiffies + 2; \
++ while (SMC_GET_MMU_CMD() & MC_BUSY) { \
++ if (time_after(jiffies, timeout)) { \
++ printk("%s: timeout %s line %d\n", \
++ dev->name, __FILE__, __LINE__); \
++ break; \
++ } \
++ } \
++ } \
++} while (0)
++
++
++/* this does a soft reset on the device */
++static void
++smc_reset(struct net_device *dev)
++{
++ unsigned long ioaddr = dev->base_addr;
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ int phyaddr = lp->phyaddr;
++ int status;
++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++ /* This resets the registers mostly to defaults, but doesn't
++ affect EEPROM. That seems unnecessary */
++ SMC_SELECT_BANK( 0 );
++ SMC_SET_RCR( RCR_SOFTRST );
++
++ /* Setup the Configuration Register */
++ /* This is necessary because the CONFIG_REG is not affected */
++ /* by a soft reset */
++ SMC_SELECT_BANK( 1 );
++ SMC_SET_CONFIG( CONFIG_DEFAULT );
++
++ /* Setup for fast accesses if requested */
++ /* If the card/system can't handle it then there will */
++ /* be no recovery except for a hard reset or power cycle */
++ if (nowait)
++ SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_NO_WAIT );
++
++#ifdef POWER_DOWN
++ /* Release from possible power-down state */
++ /* Configuration register is not affected by Soft Reset */
++ SMC_SELECT_BANK( 1 );
++ SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_EPH_POWER_EN );
++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG);
++ status &= ~PHY_CNTL_PDN;
++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG);
++#endif
++
++ /* this should pause enough for the chip to be happy */
++ udelay(1);
++
++ /* Disable transmit and receive functionality */
++ SMC_SELECT_BANK( 0 );
++ SMC_SET_RCR( RCR_CLEAR );
++ SMC_SET_TCR( TCR_CLEAR );
++
++ /* set the control register to automatically
++ release successfully transmitted packets, to make the best
++ use out of our limited memory */
++ SMC_SELECT_BANK( 1 );
++#if ! THROTTLE_TX_PKTS
++ SMC_SET_CTL( SMC_GET_CTL() | CTL_AUTO_RELEASE );
++#else
++ SMC_SET_CTL( SMC_GET_CTL() & ~CTL_AUTO_RELEASE );
++#endif
++
++ /* Disable all interrupts */
++ SMC_SELECT_BANK( 2 );
++ SMC_SET_INT_MASK( 0 );
++
++ /* Reset the MMU */
++ SMC_SET_MMU_CMD( MC_RESET );
++ SMC_WAIT_MMU_BUSY();
++}
++
++/* Enable Interrupts, Receive, and Transmit */
++static void
++smc_enable(struct net_device *dev)
++{
++ unsigned long ioaddr = dev->base_addr;
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ int mask;
++
++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++ /* see the header file for options in TCR/RCR DEFAULT*/
++ SMC_SELECT_BANK( 0 );
++ SMC_SET_TCR( lp->tcr_cur_mode );
++ SMC_SET_RCR( lp->rcr_cur_mode );
++
++ /* now, enable interrupts */
++ mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT;
++ if (lp->version >= 0x70)
++ mask |= IM_MDINT;
++ SMC_SELECT_BANK( 2 );
++ SMC_SET_INT_MASK( mask );
++}
++
++/* this puts the device in an inactive state */
++static void
++smc_shutdown(struct net_device *dev)
++{
++ int ioaddr = dev->base_addr;
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ int phyaddr = lp->phyaddr;
++ int status;
++
++ PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);
++
++ /* no more interrupts for me */
++ SMC_SELECT_BANK( 2 );
++ SMC_SET_INT_MASK( 0 );
++
++ /* and tell the card to stay away from that nasty outside world */
++ SMC_SELECT_BANK( 0 );
++ SMC_SET_RCR( RCR_CLEAR );
++ SMC_SET_TCR( TCR_CLEAR );
++
++#ifdef POWER_DOWN
++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG);
++ status |= PHY_CNTL_PDN;
++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG);
++
++ /* finally, shut the chip down */
++ SMC_SELECT_BANK( 1 );
++ SMC_SET_CONFIG( SMC_GET_CONFIG() & ~CONFIG_EPH_POWER_EN );
++#endif
++}
++
++/* This is the procedure to handle the receipt of a packet. */
++static inline void
++smc_rcv(struct net_device *dev)
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ unsigned long ioaddr = dev->base_addr;
++ unsigned int packet_number, status, packet_len;
++
++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
++
++ packet_number = SMC_GET_RXFIFO();
++ if (unlikely(packet_number & RXFIFO_REMPTY)) {
++ PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name);
++ return;
++ }
++
++ /* read from start of packet */
++ SMC_SET_PTR( PTR_READ | PTR_RCV | PTR_AUTOINC );
++
++ /* First two words are status and packet length */
++ SMC_GET_PKT_HDR(status, packet_len);
++ packet_len &= 0x07ff; /* mask off top bits */
++ PRINTK2("%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n",
++ dev->name, packet_number, status,
++ packet_len, packet_len);
++
++ if (unlikely(status & RS_ERRORS)) {
++ lp->stats.rx_errors++;
++ if (status & RS_ALGNERR)
++ lp->stats.rx_frame_errors++;
++ if (status & (RS_TOOSHORT | RS_TOOLONG))
++ lp->stats.rx_length_errors++;
++ if (status & RS_BADCRC)
++ lp->stats.rx_crc_errors++;
++ } else {
++ struct sk_buff *skb;
++ unsigned char *data;
++ unsigned int data_len;
++
++ /* set multicast stats */
++ if (status & RS_MULTICAST)
++ lp->stats.multicast++;
++
++ /*
++ * Actual payload is packet_len - 4 (or 3 if odd byte).
++ * We want skb_reserve(2) and the final ctrl word
++ * (2 bytes, possibly containing the payload odd byte).
++ * Ence packet_len - 4 + 2 + 2.
++ */
++ skb = dev_alloc_skb(packet_len);
++ if (unlikely(skb == NULL)) {
++ printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
++ dev->name);
++ lp->stats.rx_dropped++;
++ goto done;
++ }
++
++ /* Align IP header to 32 bits */
++ skb_reserve(skb, 2);
++
++ /* BUG: the LAN91C111 rev A never sets this bit. Force it. */
++ if (lp->version == 0x90)
++ status |= RS_ODDFRAME;
++
++ /*
++ * If odd length: packet_len - 3,
++ * otherwise packet_len - 4.
++ */
++ data_len = packet_len - ((status & RS_ODDFRAME) ? 3 : 4);
++ data = skb_put(skb, data_len);
++ SMC_PULL_DATA(data, packet_len - 2);
++
++ PRINT_PKT(data, packet_len - 2);
++
++ dev->last_rx = jiffies;
++ skb->dev = dev;
++ skb->protocol = eth_type_trans(skb, dev);
++ netif_rx(skb);
++ lp->stats.rx_packets++;
++ lp->stats.rx_bytes += data_len;
++ }
++
++done:
++ SMC_WAIT_MMU_BUSY();
++ SMC_SET_MMU_CMD( MC_RELEASE );
++}
++
++/*
++ * This is called to actually send a packet to the chip.
++ * Returns non-zero when successful.
++ */
++static void
++smc_hardware_send_packet(struct net_device *dev)
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ unsigned long ioaddr = dev->base_addr;
++ struct sk_buff *skb = lp->saved_skb;
++ unsigned int packet_no, len;
++ unsigned char *buf;
++
++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
++
++ if (unlikely(!skb)) {
++ printk ("%s: In XMIT with no packet to send\n", dev->name);
++ return;
++ }
++
++ packet_no = SMC_GET_AR();
++ if (unlikely(packet_no & AR_FAILED)) {
++ printk("%s: Memory allocation failed.\n", dev->name);
++ lp->saved_skb = NULL;
++ lp->stats.tx_errors++;
++ lp->stats.tx_fifo_errors++;
++ dev_kfree_skb_any(skb);
++ return;
++ }
++
++ /* point to the beginning of the packet */
++ SMC_SET_PN( packet_no );
++ SMC_SET_PTR( PTR_AUTOINC );
++
++ buf = skb->data;
++ len = skb->len;
++ PRINTK2("%s: TX PNR 0x%x lENGTH 0x%04x (%d) BUF 9x%p\n",
++ dev->name, packet_no, len, len, buf);
++ PRINT_PKT(buf, len);
++
++ /*
++ * Send the packet length ( +6 for status words, length, and ctl.
++ * The card will pad to 64 bytes with zeroes if packet is too small.
++ */
++ SMC_PUT_PKT_HDR(0, len + 6);
++
++ /* send the actual data */
++ SMC_PUSH_DATA(buf, len & ~1);
++
++ /* Send final ctl word with the last byte if there is one */
++ SMC_outw( ((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG );
++
++ /* and let the chipset deal with it */
++ SMC_SET_MMU_CMD( MC_ENQUEUE );
++ SMC_ACK_INT( IM_TX_EMPTY_INT );
++
++ dev->trans_start = jiffies;
++ dev_kfree_skb_any(skb);
++ lp->saved_skb = NULL;
++ lp->stats.tx_packets++;
++ lp->stats.tx_bytes += len;
++}
++
++/*
++ . Since I am not sure if I will have enough room in the chip's ram
++ . to store the packet, I call this routine which either sends it
++ . now, or set the card to generates an interrupt when ready
++ . for the packet.
++ */
++static int
++smc_hard_start_xmit( struct sk_buff * skb, struct net_device * dev )
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ unsigned long ioaddr = dev->base_addr;
++ unsigned int numPages, poll_count, status, saved_bank;
++
++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
++
++ if (unlikely(lp->saved_skb != NULL)) {
++ /* THIS SHOULD NEVER HAPPEN. */
++ printk( KERN_CRIT
++ "%s: Bad Craziness - sent packet while busy.\n",
++ dev->name );
++ lp->stats.tx_errors++;
++ lp->stats.tx_aborted_errors++;
++ return 1;
++ }
++ lp->saved_skb = skb;
++
++ /*
++ ** The MMU wants the number of pages to be the number of 256 bytes
++ ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
++ **
++ ** The 91C111 ignores the size bits, but the code is left intact
++ ** for backwards and future compatibility.
++ **
++ ** Pkt size for allocating is data length +6 (for additional status
++ ** words, length and ctl!)
++ **
++ ** If odd size then last byte is included in ctl word.
++ */
++ numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
++ if (unlikely(numPages > 7)) {
++ printk("%s: Far too big packet error.\n", dev->name);
++ lp->saved_skb = NULL;
++ lp->stats.tx_errors++;
++ lp->stats.tx_dropped++;
++ dev_kfree_skb(skb);
++ return 0;
++ }
++
++ /* now, try to allocate the memory */
++ saved_bank = SMC_CURRENT_BANK();
++ SMC_SELECT_BANK( 2 );
++ SMC_SET_MMU_CMD( MC_ALLOC | numPages );
++
++ /*
++ * Poll the chip for a short amount of time in case the
++ * allocation succeeds quickly.
++ */
++ poll_count = MEMORY_WAIT_TIME;
++ do {
++ status = SMC_GET_INT();
++ if (status & IM_ALLOC_INT) {
++ SMC_ACK_INT( IM_ALLOC_INT );
++ break;
++ }
++ } while (--poll_count);
++
++ if (!poll_count) {
++ /* oh well, wait until the chip finds memory later */
++ netif_stop_queue(dev);
++ PRINTK2("%s: TX memory allocation deferred.\n", dev->name);
++ SMC_ENABLE_INT( IM_ALLOC_INT );
++ } else {
++ /* Send current packet immediately.. */
++#if THROTTLE_TX_PKTS
++ netif_stop_queue(dev);
++#endif
++ smc_hardware_send_packet(dev);
++ SMC_ENABLE_INT( IM_TX_INT | IM_TX_EMPTY_INT );
++ }
++
++ SMC_SELECT_BANK( saved_bank );
++ return 0;
++}
++
++/*
++ . This handles a TX interrupt, which is only called when an error
++ . relating to a packet is sent or CTL_AUTO_RELEASE is not set.
++*/
++static void
++smc_tx(struct net_device *dev)
++{
++ unsigned long ioaddr = dev->base_addr;
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ unsigned int saved_packet, packet_no, tx_status, pkt_len;
++
++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
++
++ /* If the TX FIFO is empty then nothing to do */
++ packet_no = SMC_GET_TXFIFO();
++ if (unlikely(packet_no & TXFIFO_TEMPTY)) {
++ PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name);
++ return;
++ }
++
++ /* select packet to read from */
++ saved_packet = SMC_GET_PN();
++ SMC_SET_PN( packet_no );
++
++ /* read the first word (status word) from this packet */
++ SMC_SET_PTR( PTR_AUTOINC | PTR_READ );
++ SMC_GET_PKT_HDR(tx_status, pkt_len);
++ PRINTK2("%s: TX STATUS 0x%04x PNR 0x%02x\n",
++ dev->name, tx_status, packet_no);
++
++ if (!(tx_status & TS_SUCCESS))
++ lp->stats.tx_errors++;
++ if (tx_status & TS_LOSTCAR)
++ lp->stats.tx_carrier_errors++;
++ if (tx_status & TS_LATCOL) {
++ printk( KERN_DEBUG
++ "%s: Late collision occurred on last xmit.\n",
++ dev->name);
++ lp->stats.tx_window_errors++;
++ }
++
++ /* kill the packet */
++ SMC_WAIT_MMU_BUSY();
++ SMC_SET_MMU_CMD( MC_FREEPKT );
++
++ /* Don't restore Packet Number Reg until busy bit is cleared */
++ SMC_WAIT_MMU_BUSY();
++ SMC_SET_PN( saved_packet );
++
++ /* re-enable transmit */
++ SMC_SELECT_BANK( 0 );
++ SMC_SET_TCR( lp->tcr_cur_mode );
++ SMC_SELECT_BANK( 2 );
++}
++
++
++//---PHY CONTROL AND CONFIGURATION-----------------------------------------
++
++/*------------------------------------------------------------
++ . Debugging function for viewing MII Management serial bitstream
++ .-------------------------------------------------------------*/
++#if SMC_DEBUG > 3
++static void
++PRINT_MII_STREAM(u_char *bits, int size)
++{
++ int i;
++
++ printk("BIT#:");
++ for (i = 0; i < size; ++i)
++ printk("%d", i%10);
++
++ printk("\nMDOE:");
++ for (i = 0; i < size; ++i) {
++ if (bits[i] & MII_MDOE)
++ printk("1");
++ else
++ printk("0");
++ }
++
++ printk("\nMDO :");
++ for (i = 0; i < size; ++i) {
++ if (bits[i] & MII_MDO)
++ printk("1");
++ else
++ printk("0");
++ }
++
++ printk("\nMDI :");
++ for (i = 0; i < size; ++i) {
++ if (bits[i] & MII_MDI)
++ printk("1");
++ else
++ printk("0");
++ }
++
++ printk("\n");
++}
++#else
++#define PRINT_MII_STREAM(x...)
++#endif
++
++/*------------------------------------------------------------
++ . Reads a register from the MII Management serial interface
++ .-------------------------------------------------------------*/
++static int
++smc_read_phy_register(unsigned long ioaddr, int phyaddr, int phyreg)
++{
++ int oldBank;
++ int i, mask, mii_reg;
++ u_char bits[64];
++ int input_idx, phydata;
++ int clk_idx = 0;
++
++ // 32 consecutive ones on MDO to establish sync
++ for (i = 0; i < 32; ++i)
++ bits[clk_idx++] = MII_MDOE | MII_MDO;
++
++ // Start code <01>
++ bits[clk_idx++] = MII_MDOE;
++ bits[clk_idx++] = MII_MDOE | MII_MDO;
++
++ // Read command <10>
++ bits[clk_idx++] = MII_MDOE | MII_MDO;
++ bits[clk_idx++] = MII_MDOE;
++
++ // Output the PHY address, msb first
++ mask = 0x10;
++ for (i = 0; i < 5; ++i) {
++ if (phyaddr & mask)
++ bits[clk_idx++] = MII_MDOE | MII_MDO;
++ else
++ bits[clk_idx++] = MII_MDOE;
++
++ // Shift to next lowest bit
++ mask >>= 1;
++ }
++
++ // Output the phy register number, msb first
++ mask = 0x10;
++ for (i = 0; i < 5; ++i) {
++ if (phyreg & mask)
++ bits[clk_idx++] = MII_MDOE | MII_MDO;
++ else
++ bits[clk_idx++] = MII_MDOE;
++
++ // Shift to next lowest bit
++ mask >>= 1;
++ }
++
++ // Tristate and turnaround (2 bit times)
++ bits[clk_idx++] = 0;
++ //bits[clk_idx++] = 0;
++
++ // Input starts at this bit time
++ input_idx = clk_idx;
++
++ // Will input 16 bits
++ for (i = 0; i < 16; ++i)
++ bits[clk_idx++] = 0;
++
++ // Final clock bit
++ bits[clk_idx++] = 0;
++
++ // Save the current bank
++ oldBank = SMC_CURRENT_BANK();
++
++ // Select bank 3
++ SMC_SELECT_BANK( 3 );
++
++ // Get the current MII register value
++ mii_reg = SMC_GET_MII();
++
++ // Turn off all MII Interface bits
++ mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
++
++ // Clock all 64 cycles
++ for (i = 0; i < sizeof bits; ++i) {
++ // Clock Low - output data
++ SMC_SET_MII( mii_reg | bits[i] );
++ udelay(50);
++
++ // Clock Hi - input data
++ SMC_SET_MII( mii_reg | bits[i] | MII_MCLK );
++ udelay(50);
++ bits[i] |= SMC_GET_MII() & MII_MDI;
++ }
++
++ // Return to idle state
++ // Set clock to low, data to low, and output tristated
++ SMC_SET_MII( mii_reg );
++ udelay(50);
++
++ // Restore original bank select
++ SMC_SELECT_BANK( oldBank );
++
++ // Recover input data
++ phydata = 0;
++ for (i = 0; i < 16; ++i) {
++ phydata <<= 1;
++
++ if (bits[input_idx++] & MII_MDI)
++ phydata |= 0x0001;
++ }
++
++ PRINTK3("%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
++ __FUNCTION__, phyaddr, phyreg, phydata);
++ PRINT_MII_STREAM(bits, sizeof(bits));
++
++ return phydata;
++}
++
++/*------------------------------------------------------------
++ . Writes a register to the MII Management serial interface
++ .-------------------------------------------------------------*/
++static void
++smc_write_phy_register( unsigned long ioaddr, int phyaddr,
++ int phyreg, int phydata )
++{
++ int oldBank;
++ int i, mask, mii_reg;
++ u_char bits[65];
++ int clk_idx = 0;
++
++ // 32 consecutive ones on MDO to establish sync
++ for (i = 0; i < 32; ++i)
++ bits[clk_idx++] = MII_MDOE | MII_MDO;
++
++ // Start code <01>
++ bits[clk_idx++] = MII_MDOE;
++ bits[clk_idx++] = MII_MDOE | MII_MDO;
++
++ // Write command <01>
++ bits[clk_idx++] = MII_MDOE;
++ bits[clk_idx++] = MII_MDOE | MII_MDO;
++
++ // Output the PHY address, msb first
++ mask = 0x10;
++ for (i = 0; i < 5; ++i) {
++ if (phyaddr & mask)
++ bits[clk_idx++] = MII_MDOE | MII_MDO;
++ else
++ bits[clk_idx++] = MII_MDOE;
++
++ // Shift to next lowest bit
++ mask >>= 1;
++ }
++
++ // Output the phy register number, msb first
++ mask = 0x10;
++ for (i = 0; i < 5; ++i) {
++ if (phyreg & mask)
++ bits[clk_idx++] = MII_MDOE | MII_MDO;
++ else
++ bits[clk_idx++] = MII_MDOE;
++
++ // Shift to next lowest bit
++ mask >>= 1;
++ }
++
++ // Tristate and turnaround (2 bit times)
++ bits[clk_idx++] = 0;
++ bits[clk_idx++] = 0;
++
++ // Write out 16 bits of data, msb first
++ mask = 0x8000;
++ for (i = 0; i < 16; ++i) {
++ if (phydata & mask)
++ bits[clk_idx++] = MII_MDOE | MII_MDO;
++ else
++ bits[clk_idx++] = MII_MDOE;
++
++ // Shift to next lowest bit
++ mask >>= 1;
++ }
++
++ // Final clock bit (tristate)
++ bits[clk_idx++] = 0;
++
++ // Save the current bank
++ oldBank = SMC_CURRENT_BANK();
++
++ // Select bank 3
++ SMC_SELECT_BANK( 3 );
++
++ // Get the current MII register value
++ mii_reg = SMC_GET_MII();
++
++ // Turn off all MII Interface bits
++ mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
++
++ // Clock all cycles
++ for (i = 0; i < sizeof bits; ++i) {
++ // Clock Low - output data
++ SMC_SET_MII( mii_reg | bits[i] );
++ udelay(50);
++
++ // Clock Hi - input data
++ SMC_SET_MII( mii_reg | bits[i] | MII_MCLK );
++ udelay(50);
++ bits[i] |= SMC_GET_MII() & MII_MDI;
++ }
++
++ // Return to idle state
++ // Set clock to low, data to low, and output tristated
++ SMC_SET_MII( mii_reg );
++ udelay(50);
++
++ // Restore original bank select
++ SMC_SELECT_BANK( oldBank );
++
++ PRINTK3("%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
++ __FUNCTION__, phyaddr, phyreg, phydata);
++ PRINT_MII_STREAM(bits, sizeof(bits));
++}
++
++
++/*------------------------------------------------------------
++ . Finds and reports the PHY address
++ .-------------------------------------------------------------*/
++static int smc_detect_phy(struct net_device* dev)
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ unsigned long ioaddr = dev->base_addr;
++ int phy_id1, phy_id2;
++ int phyaddr;
++ int found = 0;
++
++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++ // Scan all 32 PHY addresses if necessary
++ for (phyaddr = 0; phyaddr < 32; ++phyaddr) {
++ // Read the PHY identifiers
++ phy_id1 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG);
++ phy_id2 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG);
++
++ PRINTK3("%s: phy_id1=0x%x, phy_id2=0x%x\n",
++ dev->name, phy_id1, phy_id2);
++
++ // Make sure it is a valid identifier
++ if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) &&
++ (phy_id1 > 0x0000) && (phy_id1 < 0xffff)) {
++ if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000)) {
++ // Save the PHY's address
++ lp->phyaddr = phyaddr;
++ found = 1;
++ break;
++ }
++ }
++ }
++
++ if (!found) {
++ PRINTK("%s: No PHY found\n", dev->name);
++ return(0);
++ }
++
++ // Set the PHY type
++ if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) ) {
++ lp->phytype = PHY_LAN83C183;
++ PRINTK("%s: PHY=LAN83C183 (LAN91C111 Internal)\n", dev->name);
++ }
++
++ if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) ) {
++ lp->phytype = PHY_LAN83C180;
++ PRINTK("%s: PHY=LAN83C180\n", dev->name);
++ }
++
++ return 1;
++}
++
++/*------------------------------------------------------------
++ . Waits the specified number of milliseconds - kernel friendly
++ .-------------------------------------------------------------*/
++static void
++smc_wait_ms(unsigned int ms)
++{
++ if (!in_interrupt()) {
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout(1 + ms * HZ / 1000);
++ } else {
++ /* if this happens it must be fixed */
++ printk( KERN_WARNING "%s: busy wait while in interrupt!\n",
++ __FUNCTION__);
++ mdelay(ms);
++ }
++}
++
++/*------------------------------------------------------------
++ . Sets the PHY to a configuration as determined by the user
++ .-------------------------------------------------------------*/
++static int
++smc_phy_fixed(struct net_device *dev)
++{
++ unsigned long ioaddr = dev->base_addr;
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ int phyaddr = lp->phyaddr;
++ int my_fixed_caps, cfg1;
++
++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
++
++ // Enter Link Disable state
++ cfg1 = smc_read_phy_register(ioaddr, phyaddr, PHY_CFG1_REG);
++ cfg1 |= PHY_CFG1_LNKDIS;
++ smc_write_phy_register(ioaddr, phyaddr, PHY_CFG1_REG, cfg1);
++
++ // Set our fixed capabilities
++ // Disable auto-negotiation
++ my_fixed_caps = 0;
++
++ if (lp->ctl_rfduplx)
++ my_fixed_caps |= PHY_CNTL_DPLX;
++
++ if (lp->ctl_rspeed == 100)
++ my_fixed_caps |= PHY_CNTL_SPEED;
++
++ // Write our capabilities to the phy control register
++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, my_fixed_caps);
++
++ // Re-Configure the Receive/Phy Control register
++ SMC_SET_RPC( lp->rpc_cur_mode );
++
++ // Success
++ return(1);
++}
++
++/*------------------------------------------------------------
++ . Configures the specified PHY through the MII management interface
++ . using Autonegotiation.
++ . Calls smc_phy_fixed() if the user has requested a certain config.
++ .-------------------------------------------------------------*/
++static void
++smc_phy_configure(struct net_device* dev)
++{
++ unsigned long ioaddr = dev->base_addr;
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ int timeout;
++ int phyaddr;
++ int my_phy_caps; // My PHY capabilities
++ int my_ad_caps; // My Advertised capabilities
++ int status;
++
++ PRINTK3("%s:smc_program_phy()\n", dev->name);
++
++ // Set the blocking flag
++ lp->autoneg_active = 1;
++
++ // Find the address and type of our phy
++ if (!smc_detect_phy(dev))
++ goto smc_phy_configure_exit;
++
++ // Get the detected phy address
++ phyaddr = lp->phyaddr;
++
++ // Reset the PHY, setting all other bits to zero
++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST);
++
++ // Wait for the reset to complete, or time out
++ timeout = 6; // Wait up to 3 seconds
++ while (timeout--) {
++ if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG)
++ & PHY_CNTL_RST))
++ // reset complete
++ break;
++ smc_wait_ms(500); // wait 500 millisecs
++ if (signal_pending(current)) { // Exit anyway if signaled
++ PRINTK("%s: PHY reset interrupted by signal\n",
++ dev->name);
++ timeout = 0;
++ break;
++ }
++ }
++
++ if (timeout < 1) {
++ printk("%s: PHY reset timed out\n", dev->name);
++ goto smc_phy_configure_exit;
++ }
++
++ // Read PHY Register 18, Status Output
++ lp->lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG);
++
++ // Enable PHY Interrupts (for register 18)
++ // Interrupts listed here are disabled
++ smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG,
++ PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD |
++ PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
++ PHY_INT_SPDDET | PHY_INT_DPLXDET);
++
++ /* Configure the Receive/Phy Control register */
++ SMC_SELECT_BANK( 0 );
++ SMC_SET_RPC( lp->rpc_cur_mode );
++
++ // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG
++ my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
++
++ // If the user requested no auto neg, then go set his request
++ if (!(lp->ctl_autoneg)) {
++ smc_phy_fixed(dev);
++ goto smc_phy_configure_exit;
++ }
++
++ if( !( my_phy_caps & PHY_STAT_CAP_ANEG))
++ {
++ printk(KERN_INFO "Auto negotiation NOT supported\n");
++ smc_phy_fixed(dev);
++ goto smc_phy_configure_exit;
++ }
++
++ my_ad_caps = PHY_AD_CSMA; // I am CSMA capable
++
++ if (my_phy_caps & PHY_STAT_CAP_T4)
++ my_ad_caps |= PHY_AD_T4;
++
++ if (my_phy_caps & PHY_STAT_CAP_TXF)
++ my_ad_caps |= PHY_AD_TX_FDX;
++
++ if (my_phy_caps & PHY_STAT_CAP_TXH)
++ my_ad_caps |= PHY_AD_TX_HDX;
++
++ if (my_phy_caps & PHY_STAT_CAP_TF)
++ my_ad_caps |= PHY_AD_10_FDX;
++
++ if (my_phy_caps & PHY_STAT_CAP_TH)
++ my_ad_caps |= PHY_AD_10_HDX;
++
++ // Disable capabilities not selected by our user
++ if (lp->ctl_rspeed != 100)
++ my_ad_caps &= ~(PHY_AD_T4|PHY_AD_TX_FDX|PHY_AD_TX_HDX);
++
++ if (!lp->ctl_rfduplx)
++ my_ad_caps &= ~(PHY_AD_TX_FDX|PHY_AD_10_FDX);
++
++ // Update our Auto-Neg Advertisement Register
++ smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps);
++
++ // Read the register back. Without this, it appears that when
++ // auto-negotiation is restarted, sometimes it isn't ready and
++ // the link does not come up.
++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_AD_REG);
++
++ PRINTK2("%s: phy caps=%x\n", dev->name, my_phy_caps);
++ PRINTK2("%s: phy advertised caps=%x\n", dev->name, my_ad_caps);
++
++ // Restart auto-negotiation process in order to advertise my caps
++ smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
++ PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST );
++
++ // Wait for the auto-negotiation to complete. This may take from
++ // 2 to 3 seconds.
++ // Wait for the reset to complete, or time out
++ timeout = 20; // Wait up to 10 seconds
++ while (timeout--) {
++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_RMT_REG);
++ if (status & PHY_AD_ACK)
++ // auto-negotiate complete
++ break;
++
++ smc_wait_ms(500); // wait 500 millisecs
++ if (signal_pending(current)) { // Exit anyway if signaled
++ printk(KERN_DEBUG
++ "%s: PHY auto-negotiate interrupted by signal\n",
++ dev->name);
++ timeout = 0;
++ break;
++ }
++ }
++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
++
++ if (timeout < 1) {
++ PRINTK("%s: PHY auto-negotiate timed out\n", dev->name);
++ }
++
++ // Fail if we detected an auto-negotiate remote fault
++ if (status & PHY_STAT_REM_FLT) {
++ PRINTK("%s: PHY remote fault detected\n", dev->name);
++ }
++
++ // Wait for link. Once the link is up, phy18 should be up to date
++ timeout = 200;
++ do
++ {
++ udelay(100);
++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
++ } while ( ((status & PHY_STAT_LINK)==0) && --timeout);
++
++ if (status & PHY_STAT_LINK)
++ {
++ PRINTK("%s: Ethernet Link Detected\n", dev->name);
++ }
++
++ // The smc_phy_interrupt() routine will be called to update lastPhy18
++
++ // Set our sysctl parameters to match auto-negotiation results
++ if ( lp->lastPhy18 & PHY_INT_SPDDET ) {
++ PRINTK("%s: PHY 100BaseT\n", dev->name);
++ lp->rpc_cur_mode |= RPC_SPEED;
++ } else {
++ PRINTK("%s: PHY 10BaseT\n", dev->name);
++ lp->rpc_cur_mode &= ~RPC_SPEED;
++ }
++
++ if ( lp->lastPhy18 & PHY_INT_DPLXDET ) {
++ PRINTK("%s: PHY Full Duplex\n", dev->name);
++ lp->rpc_cur_mode |= RPC_DPLX;
++ lp->tcr_cur_mode |= TCR_SWFDUP;
++ } else {
++ PRINTK("%s: PHY Half Duplex\n", dev->name);
++ lp->rpc_cur_mode &= ~RPC_DPLX;
++ lp->tcr_cur_mode &= ~TCR_SWFDUP;
++ }
++
++ // Re-Configure the Receive/Phy Control register and TCR
++ SMC_SET_RPC( lp->rpc_cur_mode );
++ SMC_SET_TCR( lp->tcr_cur_mode );
++
++smc_phy_configure_exit:
++ // Exit auto-negotiation
++ lp->autoneg_active = 0;
++}
++
++/*************************************************************************
++ . smc_phy_interrupt
++ .
++ . Purpose: Handle interrupts relating to PHY register 18. This is
++ . called from the "hard" interrupt handler.
++ .
++ ************************************************************************/
++static void
++smc_phy_interrupt(struct net_device* dev)
++{
++ unsigned long ioaddr = dev->base_addr;
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ int phyaddr = lp->phyaddr;
++ int phy18;
++
++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++ for(;;) {
++ // Read PHY Register 18, Status Output
++ phy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG);
++
++ // Exit if not more changes
++ if (phy18 == lp->lastPhy18)
++ break;
++
++#if SMC_DEBUG > 1
++ PRINTK2("%s: phy18=0x%04x\n", dev->name, phy18);
++ PRINTK2("%s: lastPhy18=0x%04x\n", dev->name, lp->lastPhy18);
++
++ // Handle events
++ if ((phy18 & PHY_INT_LNKFAIL) !=
++ (lp->lastPhy18 & PHY_INT_LNKFAIL))
++ PRINTK2("%s: PHY Link Fail=%x\n", dev->name,
++ phy18 & PHY_INT_LNKFAIL);
++
++ if ((phy18 & PHY_INT_LOSSSYNC) !=
++ (lp->lastPhy18 & PHY_INT_LOSSSYNC))
++ PRINTK2("%s: PHY LOSS SYNC=%x\n", dev->name,
++ phy18 & PHY_INT_LOSSSYNC);
++
++ if ((phy18 & PHY_INT_CWRD) != (lp->lastPhy18 & PHY_INT_CWRD))
++ PRINTK2("%s: PHY INVALID 4B5B code=%x\n", dev->name,
++ phy18 & PHY_INT_CWRD);
++
++ if ((phy18 & PHY_INT_SSD) != (lp->lastPhy18 & PHY_INT_SSD))
++ PRINTK2("%s: PHY No Start Of Stream=%x\n", dev->name,
++ phy18 & PHY_INT_SSD);
++
++ if ((phy18 & PHY_INT_ESD) != (lp->lastPhy18 & PHY_INT_ESD))
++
++ PRINTK2("%s: PHY No End Of Stream=%x\n", dev->name,
++ phy18 & PHY_INT_ESD);
++
++ if ((phy18 & PHY_INT_RPOL) != (lp->lastPhy18 & PHY_INT_RPOL))
++ PRINTK2("%s: PHY Reverse Polarity Detected=%x\n",
++ dev->name, phy18 & PHY_INT_RPOL);
++
++ if ((phy18 & PHY_INT_JAB) != (lp->lastPhy18 & PHY_INT_JAB))
++ PRINTK2("%s: PHY Jabber Detected=%x\n", dev->name,
++ phy18 & PHY_INT_JAB);
++
++ if ((phy18 & PHY_INT_SPDDET) !=
++ (lp->lastPhy18 & PHY_INT_SPDDET))
++ PRINTK2("%s: PHY Speed Detect=%x\n", dev->name,
++ phy18 & PHY_INT_SPDDET);
++
++ if ((phy18 & PHY_INT_DPLXDET) !=
++ (lp->lastPhy18 & PHY_INT_DPLXDET))
++ PRINTK2("%s: PHY Duplex Detect=%x\n", dev->name,
++ phy18 & PHY_INT_DPLXDET);
++#endif
++ // Update the last phy 18 variable
++ lp->lastPhy18 = phy18;
++ }
++}
++
++//--- END PHY CONTROL AND CONFIGURATION-------------------------------------
++
++
++/*
++ * This is the main routine of the driver, to handle the device when
++ * it needs some attention.
++ */
++static void
++smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct net_device *dev = dev_id;
++ unsigned long ioaddr = dev->base_addr;
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ int status, mask, timeout, card_stats;
++ int saved_bank, saved_pointer;
++
++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
++
++ saved_bank = SMC_CURRENT_BANK();
++ SMC_SELECT_BANK(2);
++ saved_pointer = SMC_GET_PTR();
++ mask = SMC_GET_INT_MASK();
++ SMC_SET_INT_MASK( 0 );
++
++ /* set a timeout value, so I don't stay here forever */
++ timeout = 8;
++
++ do {
++ status = SMC_GET_INT();
++
++ PRINTK2("%s: IRQ 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n",
++ dev->name, status, mask,
++ ({ int meminfo; SMC_SELECT_BANK(0);
++ meminfo = SMC_GET_MIR();
++ SMC_SELECT_BANK(2); meminfo; }),
++ SMC_GET_FIFO());
++
++ status &= mask;
++ if (!status)
++ break;
++
++ if (status & IM_RCV_INT) {
++ PRINTK3("%s: RX irq\n", dev->name);
++ smc_rcv(dev);
++ } else if (status & IM_TX_INT) {
++ PRINTK3("%s: TX int\n", dev->name);
++ smc_tx(dev);
++ SMC_ACK_INT( IM_TX_INT );
++#if THROTTLE_TX_PKTS
++ netif_wake_queue(dev);
++#endif
++ } else if (status & IM_ALLOC_INT) {
++ PRINTK3("%s: Allocation irq\n", dev->name);
++ smc_hardware_send_packet(dev);
++ mask |= (IM_TX_INT | IM_TX_EMPTY_INT);
++ mask &= ~IM_ALLOC_INT;
++#if ! THROTTLE_TX_PKTS
++ netif_wake_queue(dev);
++#endif
++ } else if (status & IM_TX_EMPTY_INT) {
++ PRINTK3("%s: TX empty\n", dev->name);
++ mask &= ~IM_TX_EMPTY_INT;
++
++ /* update stats */
++ SMC_SELECT_BANK( 0 );
++ card_stats = SMC_GET_COUNTER();
++ SMC_SELECT_BANK( 2 );
++
++ /* single collisions */
++ lp->stats.collisions += card_stats & 0xF;
++ card_stats >>= 4;
++
++ /* multiple collisions */
++ lp->stats.collisions += card_stats & 0xF;
++ } else if (status & IM_RX_OVRN_INT) {
++ PRINTK1( "%s: RX overrun\n", dev->name);
++ SMC_ACK_INT( IM_RX_OVRN_INT );
++ lp->stats.rx_errors++;
++ lp->stats.rx_fifo_errors++;
++ } else if (status & IM_EPH_INT) {
++ PRINTK("%s: UNSUPPORTED: EPH INTERRUPT\n", dev->name);
++ } else if (status & IM_MDINT) {
++ SMC_ACK_INT( IM_MDINT );
++ smc_phy_interrupt(dev);
++ } else if (status & IM_ERCV_INT ) {
++ SMC_ACK_INT( IM_ERCV_INT );
++ PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name);
++ }
++ } while (--timeout);
++
++ /* restore register states */
++ SMC_SET_INT_MASK( mask );
++ SMC_SET_PTR( saved_pointer );
++ SMC_SELECT_BANK( saved_bank );
++
++ PRINTK3("%s: Interrupt done\n", dev->name);
++}
++
++/* Our watchdog timed out. Called by the networking layer */
++static void
++smc_timeout(struct net_device *dev)
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++
++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++ smc_reset(dev);
++ smc_enable(dev);
++
++#if 0
++ /* Reconfiguring the PHY doesn't seem like a bad idea here, but
++ * it introduced a problem. Now that this is a timeout routine,
++ * we are getting called from within an interrupt context.
++ * smc_phy_configure() calls smc_wait_ms() which calls
++ * schedule_timeout() which calls schedule(). When schedule()
++ * is called from an interrupt context, it prints out
++ * "Scheduling in interrupt" and then calls BUG(). This is
++ * obviously not desirable. This was worked around by removing
++ * the call to smc_phy_configure() here because it didn't seem
++ * absolutely necessary. Ultimately, if smc_wait_ms() is
++ * supposed to be usable from an interrupt context (which it
++ * looks like it thinks it should handle), it should be fixed.
++ */
++ /* Reconfigure the PHY */
++ smc_phy_configure(dev);
++#endif
++
++ /* clear anything saved */
++ if (lp->saved_skb != NULL) {
++ dev_kfree_skb (lp->saved_skb);
++ lp->saved_skb = NULL;
++ lp->stats.tx_errors++;
++ lp->stats.tx_aborted_errors++;
++ }
++ dev->trans_start = jiffies;
++ netif_wake_queue(dev);
++}
++
++/*
++ * Finds the CRC32 of a set of bytes.
++ * (from Peter Cammaert's code)
++ */
++static int
++crc32(char *s, int length)
++{
++ /* indices */
++ int perByte;
++ int perBit;
++ /* crc polynomial for Ethernet */
++ const unsigned long poly = 0xedb88320;
++ /* crc value - preinitialized to all 1's */
++ unsigned long crc_value = 0xffffffff;
++
++ for ( perByte = 0; perByte < length; perByte ++ ) {
++ unsigned char c;
++
++ c = *(s++);
++ for ( perBit = 0; perBit < 8; perBit++ ) {
++ crc_value = (crc_value>>1)^
++ (((crc_value^c)&0x01)?poly:0);
++ c >>= 1;
++ }
++ }
++ return crc_value;
++}
++
++/*
++ . This sets the internal hardware table to filter out unwanted multicast
++ . packets before they take up memory.
++ .
++ . The SMC chip uses a hash table where the high 6 bits of the CRC of
++ . address are the offset into the table. If that bit is 1, then the
++ . multicast packet is accepted. Otherwise, it's dropped silently.
++ .
++ . To use the 6 bits as an offset into the table, the high 3 bits are the
++ . number of the 8 bit register, while the low 3 bits are the bit within
++ . that register.
++ .
++ . This routine is based very heavily on the one provided by Peter Cammaert.
++*/
++static void
++smc_setmulticast(unsigned long ioaddr, int count, struct dev_mc_list *addrs)
++{
++ int i;
++ unsigned char multicast_table[ 8 ];
++ struct dev_mc_list *cur_addr;
++
++ /* table for flipping the order of 3 bits */
++ static unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
++
++ /* start with a table of all zeros: reject all */
++ memset( multicast_table, 0, sizeof( multicast_table ) );
++
++ cur_addr = addrs;
++ for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) {
++ int position;
++
++ /* do we have a pointer here? */
++ if ( !cur_addr )
++ break;
++ /* make sure this is a multicast address - shouldn't this
++ be a given if we have it here ? */
++ if ( !( *cur_addr->dmi_addr & 1 ) )
++ continue;
++
++ /* only use the low order bits */
++ position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f;
++
++ /* do some messy swapping to put the bit in the right spot */
++ multicast_table[invert3[position&7]] |=
++ (1<<invert3[(position>>3)&7]);
++
++ }
++ /* now, the table can be loaded into the chipset */
++ SMC_SELECT_BANK( 3 );
++ SMC_SET_MCAST( multicast_table );
++}
++
++/*
++ . This routine will, depending on the values passed to it,
++ . either make it accept multicast packets, go into
++ . promiscuous mode ( for TCPDUMP and cousins ) or accept
++ . a select set of multicast packets
++*/
++static void smc_set_multicast_list(struct net_device *dev)
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ unsigned long ioaddr = dev->base_addr;
++
++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++ SMC_SELECT_BANK(0);
++ if ( dev->flags & IFF_PROMISC ) {
++ PRINTK2("%s: RCR_PRMS\n", dev->name);
++ lp->rcr_cur_mode |= RCR_PRMS;
++ SMC_SET_RCR( lp->rcr_cur_mode );
++ }
++
++/* BUG? I never disable promiscuous mode if multicasting was turned on.
++ Now, I turn off promiscuous mode, but I don't do anything to multicasting
++ when promiscuous mode is turned on.
++*/
++
++ /* Here, I am setting this to accept all multicast packets.
++ I don't need to zero the multicast table, because the flag is
++ checked before the table is
++ */
++ else if (dev->flags & IFF_ALLMULTI) {
++ lp->rcr_cur_mode |= RCR_ALMUL;
++ SMC_SET_RCR( lp->rcr_cur_mode );
++ PRINTK2("%s: RCR_ALMUL\n", dev->name);
++ }
++
++ /* We just get all multicast packets even if we only want them
++ . from one source. This will be changed at some future
++ . point. */
++ else if (dev->mc_count ) {
++ /* support hardware multicasting */
++
++ /* be sure I get rid of flags I might have set */
++ lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
++ SMC_SET_RCR( lp->rcr_cur_mode );
++ /* NOTE: this has to set the bank, so make sure it is the
++ last thing called. The bank is set to zero at the top */
++ smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );
++ } else {
++ PRINTK2("%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name);
++ lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
++ SMC_SET_RCR( lp->rcr_cur_mode );
++
++ /*
++ since I'm disabling all multicast entirely, I need to
++ clear the multicast list
++ */
++ SMC_SELECT_BANK( 3 );
++ SMC_CLEAR_MCAST();
++ }
++}
++
++
++/*
++ * Open and Initialize the board
++ *
++ * Set up everything, reset the card, etc ..
++ */
++static int
++smc_open(struct net_device *dev)
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ unsigned long ioaddr = dev->base_addr;
++
++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++ /* clear out all the junk that was put here before... */
++ memset(dev->priv, 0, sizeof(struct smc_local));
++
++ // Setup the default Register Modes
++ lp->tcr_cur_mode = TCR_DEFAULT;
++ lp->rcr_cur_mode = RCR_DEFAULT;
++ lp->rpc_cur_mode = RPC_DEFAULT;
++
++ /* Set default parameters */
++#ifdef CONFIG_ARCH_RAMSES
++ lp->ctl_autoneg = 0;
++ lp->ctl_rfduplx = 0;
++ lp->ctl_rspeed = 10;
++#else
++ lp->ctl_autoneg = 1;
++ lp->ctl_rfduplx = 1;
++ lp->ctl_rspeed = 100;
++#endif
++
++ SMC_SELECT_BANK(3);
++ lp->version = SMC_GET_REV() & 0xff;
++
++ /* reset the hardware */
++ smc_reset(dev);
++ smc_enable(dev);
++
++ SMC_SELECT_BANK( 1 );
++ SMC_SET_MAC_ADDR(dev->dev_addr);
++
++ /* Configure the PHY */
++ if (lp->version >= 0x70)
++ smc_phy_configure(dev);
++
++ netif_start_queue(dev);
++ return 0;
++}
++
++/*----------------------------------------------------
++ . smc_close
++ .
++ . this makes the board clean up everything that it can
++ . and not talk to the outside world. Caused by
++ . an 'ifconfig ethX down'
++ .
++ -----------------------------------------------------*/
++static int
++smc_close(struct net_device *dev)
++{
++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++ netif_stop_queue(dev);
++
++ /* clear everything */
++ smc_shutdown(dev);
++
++ return 0;
++}
++
++/*------------------------------------------------------------
++ . Get the current statistics.
++ . This may be called with the card open or closed.
++ .-------------------------------------------------------------*/
++static struct net_device_stats *
++smc_query_statistics(struct net_device *dev)
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++
++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++ return &lp->stats;
++}
++
++/*----------------------------------------------------------------------
++ . smc_findirq
++ .
++ . This routine has a simple purpose -- make the SMC chip generate an
++ . interrupt, so an auto-detect routine can detect it, and find the IRQ,
++ ------------------------------------------------------------------------
++*/
++int __init
++smc_findirq( unsigned long ioaddr )
++{
++ int timeout = 20;
++ unsigned long cookie;
++
++ PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);
++
++ cookie = probe_irq_on();
++
++ /*
++ * What I try to do here is trigger an ALLOC_INT. This is done
++ * by allocating a small chunk of memory, which will give an interrupt
++ * when done.
++ */
++
++ /* enable ALLOCation interrupts ONLY */
++ SMC_SELECT_BANK(2);
++ SMC_SET_INT_MASK( IM_ALLOC_INT );
++
++ /*
++ . Allocate 512 bytes of memory. Note that the chip was just
++ . reset so all the memory is available
++ */
++ SMC_SET_MMU_CMD( MC_ALLOC | 1 );
++
++ /*
++ . Wait until positive that the interrupt has been generated
++ */
++ do {
++ int int_status;
++ udelay(10);
++ int_status = SMC_GET_INT();
++ if (int_status & IM_ALLOC_INT)
++ break; /* got the interrupt */
++ } while (--timeout);
++
++ /* there is really nothing that I can do here if timeout fails,
++ as autoirq_report will return a 0 anyway, which is what I
++ want in this case. Plus, the clean up is needed in both
++ cases. */
++
++ /* and disable all interrupts again */
++ SMC_SET_INT_MASK( 0 );
++
++ /* and return what I found */
++ return probe_irq_off(cookie);
++}
++
++/*----------------------------------------------------------------------
++ . Function: smc_probe( unsigned long ioaddr )
++ .
++ . Purpose:
++ . Tests to see if a given ioaddr points to an SMC91x chip.
++ . Returns a 0 on success
++ .
++ . Algorithm:
++ . (1) see if the high byte of BANK_SELECT is 0x33
++ . (2) compare the ioaddr with the base register's address
++ . (3) see if I recognize the chip ID in the appropriate register
++ .
++ .---------------------------------------------------------------------
++ */
++/*---------------------------------------------------------------
++ . Here I do typical initialization tasks.
++ .
++ . o Initialize the structure if needed
++ . o print out my vanity message if not done so already
++ . o print out what type of hardware is detected
++ . o print out the ethernet address
++ . o find the IRQ
++ . o set up my private data
++ . o configure the dev structure with my subroutines
++ . o actually GRAB the irq.
++ . o GRAB the region
++ .-----------------------------------------------------------------
++*/
++static int __init
++smc_probe(struct net_device *dev, unsigned long ioaddr)
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ static int version_printed = 0;
++ int i, retval;
++ unsigned int val, revision_register;
++ const char *version_string;
++
++ PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);
++
++ /* Grab the region so that no one else tries to probe our ioports. */
++ if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name))
++ return -EBUSY;
++
++ /* First, see if the high byte is 0x33 */
++ val = SMC_CURRENT_BANK();
++ PRINTK2("%s: bank signature probe returned 0x%04x\n", CARDNAME, val);
++ if ( (val & 0xFF00) != 0x3300 ) {
++ if ( (val & 0xFF) == 0x33 ) {
++ printk( KERN_WARNING
++ "%s: Detected possible byte-swapped interface"
++ " at IOADDR 0x%lx\n", CARDNAME, ioaddr);
++ }
++ retval = -ENODEV;
++ goto err_out;
++ }
++
++ /* The above MIGHT indicate a device, but I need to write to further
++ test this. */
++ SMC_SELECT_BANK(0);
++ val = SMC_CURRENT_BANK();
++ if ( (val & 0xFF00 ) != 0x3300 ) {
++ retval = -ENODEV;
++ goto err_out;
++ }
++
++ /* well, we've already written once, so hopefully another time won't
++ hurt. This time, I need to switch the bank register to bank 1,
++ so I can access the base address register */
++ SMC_SELECT_BANK(1);
++ val = SMC_GET_BASE();
++ val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT;
++ if ( (ioaddr & ((PAGE_SIZE-1)<<SMC_IO_SHIFT)) != val ) {
++ printk( "%s: IOADDR %lx doesn't match configuration (%x).\n",
++ CARDNAME, ioaddr, val );
++ }
++
++ /* check if the revision register is something that I recognize.
++ These might need to be added to later, as future revisions
++ could be added. */
++ SMC_SELECT_BANK(3);
++ revision_register = SMC_GET_REV();
++ PRINTK2("%s: revision = 0x%04x\n", CARDNAME, revision_register);
++ version_string = chip_ids[ (revision_register >> 4) & 0xF];
++ if (!version_string || (revision_register & 0xff00) != 0x3300) {
++ /* I don't recognize this chip, so... */
++ printk( "%s: IO 0x%lx: Unrecognized revision register 0x%04x"
++ ", Contact author.\n", CARDNAME,
++ ioaddr, revision_register);
++
++ retval = -ENODEV;
++ goto err_out;
++ }
++
++ /* At this point I'll assume that the chip is an SMC91x. */
++ if (version_printed++ == 0)
++ printk("%s", version);
++
++ /* set the private data to zero by default */
++ memset(lp, 0, sizeof(struct smc_local));
++
++ /* fill in some of the fields */
++ dev->base_addr = ioaddr;
++ lp->version = revision_register & 0xff;
++
++ /* Get the MAC address */
++ SMC_SELECT_BANK( 1 );
++ SMC_GET_MAC_ADDR(dev->dev_addr);
++
++ /* now, reset the chip, and put it into a known state */
++ smc_reset( dev );
++
++ /*
++ . If dev->irq is 0, then the device has to be banged on to see
++ . what the IRQ is.
++ .
++ . This banging doesn't always detect the IRQ, for unknown reasons.
++ . a workaround is to reset the chip and try again.
++ .
++ . Interestingly, the DOS packet driver *SETS* the IRQ on the card to
++ . be what is requested on the command line. I don't do that, mostly
++ . because the card that I have uses a non-standard method of accessing
++ . the IRQs, and because this _should_ work in most configurations.
++ .
++ . Specifying an IRQ is done with the assumption that the user knows
++ . what (s)he is doing. No checking is done!!!!
++ .
++ */
++ if ( dev->irq < 1 ) {
++ int trials;
++
++ trials = 3;
++ while ( trials-- ) {
++ dev->irq = smc_findirq( ioaddr );
++ if ( dev->irq )
++ break;
++ /* kick the card and try again */
++ smc_reset( dev );
++ }
++ }
++ if (dev->irq == 0 ) {
++ printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",
++ dev->name);
++ retval = -ENODEV;
++ goto err_out;
++ }
++ dev->irq = irq_cannonicalize(dev->irq);
++
++ /* now, print out the card info, in a short format.. */
++ printk( "%s: %s (rev %d) at %#lx IRQ %d%s%s\n",
++ dev->name, version_string, revision_register & 0x0f,
++ ioaddr, dev->irq, nowait ? " [nowait]" : "",
++ THROTTLE_TX_PKTS ? " [throttle_tx]" : "" );
++
++ /* Print the Ethernet address */
++ printk("%s: Ethernet addr: ", dev->name);
++ for (i = 0; i < 5; i++)
++ printk("%2.2x:", dev->dev_addr[i] );
++ printk("%2.2x\n", dev->dev_addr[5] );
++
++ /* Fill in the fields of the device structure with ethernet values. */
++ ether_setup(dev);
++
++ /* Grab the IRQ */
++ retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev);
++ if (retval) {
++ goto err_out;
++ }
++
++ dev->open = smc_open;
++ dev->stop = smc_close;
++ dev->hard_start_xmit = smc_hard_start_xmit;
++ dev->tx_timeout = smc_timeout;
++ dev->watchdog_timeo = HZ/10;
++ dev->get_stats = smc_query_statistics;
++ dev->set_multicast_list = smc_set_multicast_list;
++
++ return 0;
++
++err_out:
++ release_region(ioaddr, SMC_IO_EXTENT);
++ return retval;
++}
++
++/*-------------------------------------------------------------------------
++ |
++ | smc_init( void )
++ | Input parameters:
++ | dev->base_addr == 0, try to find all possible locations
++ | dev->base_addr > 0x1ff, this is the address to check
++ | dev->base_addr == <anything else>, return failure code
++ |
++ | Output:
++ | 0 --> there is a device
++ | anything else, error
++ |
++ ---------------------------------------------------------------------------
++*/
++static struct net_device *global_dev = NULL; /* needs to be fixed */
++
++#ifdef CONFIG_PM
++
++static int smc_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
++{
++ unsigned long ioaddr = global_dev->base_addr;
++ struct smc_local *lp = (struct smc_local *)global_dev->priv;
++
++ switch (rqst) {
++ case PM_SUSPEND:
++ smc_shutdown(global_dev);
++ break;
++ case PM_RESUME:
++ smc_reset(global_dev);
++ smc_enable(global_dev);
++ SMC_SELECT_BANK( 1 );
++ SMC_SET_MAC_ADDR(global_dev->dev_addr);
++ if (lp->version >= 0x70)
++ smc_phy_configure(global_dev);
++ break;
++ }
++ return 0;
++}
++
++#endif
++
++static int __init
++smc_init(void)
++{
++ int ret;
++
++ PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);
++
++#ifdef MODULE
++ if (io == -1)
++ printk( KERN_WARNING
++ "%s: You shouldn't use auto-probing with insmod!\n",
++ CARDNAME );
++#endif
++
++ if (global_dev) {
++ printk("%s: already initialized.\n", CARDNAME);
++ return -EBUSY;
++ }
++
++ global_dev = init_etherdev(0, sizeof(struct smc_local));
++ if (!global_dev) {
++ printk("%s: could not allocate device.\n", CARDNAME);
++ return -ENOMEM;
++ }
++ SET_MODULE_OWNER(global_dev);
++
++ /* copy the parameters from insmod into the device structure */
++ if (io != -1)
++ global_dev->base_addr = io;
++ if (irq != -1)
++ global_dev->irq = irq;
++
++#ifdef CONFIG_ISA
++ /* try a specific location */
++ if (global_dev->base_addr > 0x1ff)
++ ret = smc_probe(global_dev, global_dev->base_addr);
++ else if (global_dev->base_addr != 0)
++ ret = -ENXIO;
++ else {
++ int i;
++
++ /* check every ethernet address */
++ for (i = 0; smc_portlist[i]; i++) {
++ ret = smc_probe(global_dev, smc_portlist[i]);
++ if (ret == 0)
++ break;
++ }
++ }
++#elif defined(CONFIG_ARCH_LUBBOCK)
++ {
++ int ioaddr = LUBBOCK_ETH_VIRT + (0x300 << 2);
++ volatile int *attaddr = (int *)(LUBBOCK_ETH_VIRT + 0x100000);
++ unsigned long flags;
++
++ /* first reset, then enable the device. Sequence is critical */
++ local_irq_save(flags);
++ attaddr[ECOR] |= ECOR_RESET;
++ udelay(100);
++ attaddr[ECOR] &= ~ECOR_RESET;
++ attaddr[ECOR] |= ECOR_ENABLE;
++
++ /* force 16-bit mode */
++ attaddr[ECSR] &= ~ECSR_IOIS8;
++ mdelay(1);
++ local_irq_restore(flags);
++
++ global_dev->irq = LUBBOCK_ETH_IRQ;
++ ret = smc_probe(global_dev, ioaddr);
++ }
++#elif defined(CONFIG_ARCH_PXA_IDP)
++ {
++ int ioaddr = IDP_ETH_BASE + 0x300;
++ global_dev->irq = SMC_IRQ;
++ ret = smc_probe(global_dev, ioaddr);
++ }
++#elif defined(CONFIG_ARCH_RAMSES)
++ {
++ int ioaddr = RAMSES_ETH_BASE + 0x300;
++ global_dev->irq = SMC_IRQ;
++ ret = smc_probe(global_dev, ioaddr);
++ }
++#else
++ if (global_dev->base_addr == -1) {
++ printk(KERN_WARNING"%s: SMC91X_BASE_ADDR not set!\n", CARDNAME);
++ ret = -ENXIO;
++ } else {
++ void *ioaddr = ioremap(global_dev->base_addr, SMC_IO_EXTENT);
++ ret = smc_probe(global_dev, (unsigned long)ioaddr);
++ if (ret != 0)
++ iounmap(ioaddr);
++ }
++#endif
++
++#ifdef SMC_USE_PXA_DMA
++ if (ret == 0) {
++ int dma = pxa_request_dma(global_dev->name, DMA_PRIO_LOW,
++ smc_pxa_dma_irq, NULL);
++ if (dma >= 0) {
++ global_dev->dma = dma;
++ PRINTK("%s: using DMA channel %d\n", global_dev->name, dma);
++ } else {
++ global_dev->dma = -1;
++ }
++ }
++#endif
++
++#ifdef CONFIG_PM
++ if (ret == 0) {
++ struct smc_local *lp = (struct smc_local *)global_dev->priv;
++ lp->pm = pm_register(PM_SYS_UNKNOWN, 0x73393178, smc_pm_callback);
++ }
++#endif
++
++ if (ret != 0) {
++ printk("%s: not found.\n", CARDNAME);
++ kfree(global_dev->priv);
++ unregister_netdev(global_dev);
++ kfree(global_dev);
++ }
++
++ return ret;
++}
++
++static void __exit
++smc_cleanup(void)
++{
++ unregister_netdev(global_dev);
++#ifdef CONFIG_PM
++ {
++ struct smc_local *lp = (struct smc_local *)global_dev->priv;
++ pm_unregister(lp->pm);
++ }
++#endif
++ free_irq(global_dev->irq, global_dev);
++ release_region(global_dev->base_addr, SMC_IO_EXTENT);
++
++#ifndef CONFIG_ISA
++ iounmap((void *)global_dev->base_addr);
++#endif
++
++ kfree(global_dev);
++ global_dev = NULL;
++}
++
++module_init(smc_init);
++module_exit(smc_cleanup);
++
+--- /dev/null
++++ linux-2.4.27/drivers/net/smc91x.h
+@@ -0,0 +1,835 @@
++/*------------------------------------------------------------------------
++ . smc91x.h - macros for SMSC's 91C9x/91C1xx single-chip Ethernet device.
++ .
++ . Copyright (C) 1996 by Erik Stahlman
++ . Copyright (C) 2001 Standard Microsystems Corporation
++ . Developed by Simple Network Magic Corporation
++ . Copyright (C) 2003 Monta Vista Software, Inc.
++ . Unified SMC91x driver by Nicolas Pitre
++ .
++ . This program is free software; you can redistribute it and/or modify
++ . it under the terms of the GNU General Public License as published by
++ . the Free Software Foundation; either version 2 of the License, or
++ . (at your option) any later version.
++ .
++ . This program is distributed in the hope that it will be useful,
++ . but WITHOUT ANY WARRANTY; without even the implied warranty of
++ . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ . GNU General Public License for more details.
++ .
++ . You should have received a copy of the GNU General Public License
++ . along with this program; if not, write to the Free Software
++ . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ .
++ . Information contained in this file was obtained from the LAN91C111
++ . manual from SMC. To get a copy, if you really want one, you can find
++ . information under www.smsc.com.
++ .
++ . Authors
++ . Erik Stahlman <erik@vt.edu>
++ . Daris A Nevil <dnevil@snmc.com>
++ . Nicolas Pitre <nico@cam.org>
++ .
++ ---------------------------------------------------------------------------*/
++#ifndef _SMC91X_H_
++#define _SMC91X_H_
++
++
++/*
++ * Define your architecture specific configuration parameters here.
++ */
++
++#if defined(CONFIG_SA1100_GRAPHICSCLIENT) || \
++ defined(CONFIG_SA1100_PFS168) || \
++ defined(CONFIG_SA1100_FLEXANET) || \
++ defined(CONFIG_SA1100_GRAPHICSMASTER) || \
++ defined(CONFIG_ARCH_LUBBOCK)
++
++/* We can only do 16-bit reads and writes in the static memory space. */
++#define SMC_CAN_USE_8BIT 0
++#define SMC_CAN_USE_16BIT 1
++#define SMC_CAN_USE_32BIT 0
++#define SMC_NOWAIT 1
++
++/* The first two address lines aren't connected... */
++#define SMC_IO_SHIFT 2
++
++#define SMC_inw(a, r) readw((a) + (r))
++#define SMC_outw(v, a, r) writew(v, (a) + (r))
++#define SMC_insw(a, r, p, l) insw((a) + (r), p, l)
++#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l)
++
++#ifdef CONFIG_ARCH_LUBBOCK
++#define SMC_IOADDR LUBBOCK_ETH_PHYS
++#endif
++
++#elif defined(CONFIG_ARCH_MAINSTONE) || defined(CONFIG_ARCH_PXA_IDP) || defined(CONFIG_ARCH_RAMSES)
++
++#ifdef CONFIG_ARCH_MAINSTONE
++#include <asm/arch/mainstone.h>
++#define SMC_IOADDR (MST_ETH_PHYS + 0x300)
++#define SMC_IRQ MAINSTONE_IRQ(3)
++
++#elif CONFIG_ARCH_PXA_IDP
++#include <asm/arch/idp.h>
++#define SMC_IOADDR (IDP_ETH_PHYS + 0x300)
++#define SMC_IRQ ETHERNET_IRQ
++
++#elif CONFIG_ARCH_RAMSES
++#include <asm/arch/ramses.h>
++#define SMC_IOADDR (RAMSES_ETH_PHYS + 0x300)
++#define SMC_IRQ ETHERNET_IRQ
++#endif
++
++#define SMC_CAN_USE_8BIT 1
++#define SMC_CAN_USE_16BIT 1
++#define SMC_CAN_USE_32BIT 1
++#define SMC_IO_SHIFT 0
++#define SMC_NOWAIT 1
++#define SMC_USE_PXA_DMA 1
++
++#define SMC_inb(a, r) readb((a) + (r))
++#define SMC_inw(a, r) readw((a) + (r))
++#define SMC_inl(a, r) readl((a) + (r))
++#define SMC_outb(v, a, r) writeb(v, (a) + (r))
++#define SMC_outl(v, a, r) writel(v, (a) + (r))
++#define SMC_insl(a, r, p, l) insl((a) + (r), p, l)
++#define SMC_outsl(a, r, p, l) outsl((a) + (r), p, l)
++
++/* We actually can't write halfwords properly if not word aligned */
++static inline void
++SMC_outw(u16 val, unsigned long ioaddr, int reg)
++{
++ if (reg & 2) {
++ unsigned int v = val << 16;
++ v |= readl(ioaddr + (reg & ~2)) & 0xffff;
++ writel(v, ioaddr + (reg & ~2));
++ } else {
++ writew(val, ioaddr + reg);
++ }
++}
++
++#elif defined(CONFIG_ISA)
++
++#define SMC_CAN_USE_8BIT 1
++#define SMC_CAN_USE_16BIT 1
++#define SMC_CAN_USE_32BIT 0
++
++#define SMC_inb(a, r) inb((a) + (r))
++#define SMC_inw(a, r) inw((a) + (r))
++#define SMC_outb(v, a, r) outb(v, (a) + (r))
++#define SMC_outw(v, a, r) outw(v, (a) + (r))
++#define SMC_insw(a, r, p, l) insw((a) + (r), p, l)
++#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l)
++
++#endif
++
++
++#ifdef SMC_USE_PXA_DMA
++/*
++ * Let's use the DMA engine on the XScale PXA2xx for RX packets. This is
++ * always happening in irq context so no need to worry about races. TX is
++ * different and probably not worth it for that reason, and not as critical
++ * as RX which can overrun memory and lose packets.
++ */
++#include <linux/pci.h>
++#include <asm/dma.h>
++
++#ifdef SMC_insl
++#undef SMC_insl
++#define SMC_insl(a, r, p, l) smc_pxa_dma_insl(a, r, dev->dma, p, l)
++static inline void
++smc_pxa_dma_insl(u_long ioaddr, int reg, int dma, u_char *buf, int len)
++{
++ dma_addr_t dmabuf;
++
++ /* fallback if no DMA available */
++ if (dma == -1) {
++ insl(ioaddr + reg, buf, len);
++ return;
++ }
++
++ /* 64 bit alignment is required for memory to memory DMA */
++ if ((long)buf & 4) {
++ *((u32 *)buf)++ = SMC_inl(ioaddr, reg);
++ len--;
++ }
++
++ len *= 4;
++ dmabuf = pci_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE);
++ DCSR(dma) = DCSR_NODESC;
++ DTADR(dma) = dmabuf;
++ DSADR(dma) = SMC_IOADDR + reg;
++ DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
++ DCMD_WIDTH4 | (DCMD_LENGTH & len));
++ DCSR(dma) = DCSR_NODESC | DCSR_RUN;
++ while (!(DCSR(dma) & DCSR_STOPSTATE));
++ DCSR(dma) = 0;
++ pci_unmap_single(NULL, dmabuf,len, PCI_DMA_FROMDEVICE);
++}
++#endif
++
++#ifdef SMC_insw
++#undef SMC_insw
++#define SMC_insw(a, r, p, l) smc_pxa_dma_insw(a, r, dev->dma, p, l)
++static inline void
++smc_pxa_dma_insw(u_long ioaddr, int reg, int dma, u_char *buf, int len)
++{
++ dma_addr_t dmabuf;
++
++ /* fallback if no DMA available */
++ if (dma == -1) {
++ insw(ioaddr + reg, buf, len);
++ return;
++ }
++
++ /* 64 bit alignment is required for memory to memory DMA */
++ while ((long)buf & 6) {
++ *((u16 *)buf)++ = SMC_inw(ioaddr, reg);
++ len--;
++ }
++
++ len *= 2;
++ dmabuf = pci_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE);
++ DCSR(dma) = DCSR_NODESC;
++ DTADR(dma) = dmabuf;
++ DSADR(dma) = SMC_IOADDR + reg;
++ DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
++ DCMD_WIDTH2 | (DCMD_LENGTH & len));
++ DCSR(dma) = DCSR_NODESC | DCSR_RUN;
++ while (!(DCSR(dma) & DCSR_STOPSTATE));
++ DCSR(dma) = 0;
++ pci_unmap_single(NULL, dmabuf,len, PCI_DMA_FROMDEVICE);
++}
++#endif
++
++static void
++smc_pxa_dma_irq(int dma, void *dummy, struct pt_regs *regs)
++{
++ DCSR(dma) = 0;
++}
++#endif /* SMC_USE_PXA_DMA */
++
++
++/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */
++#ifndef SMC_IO_SHIFT
++#define SMC_IO_SHIFT 0
++#endif
++#define SMC_IO_EXTENT (16 << SMC_IO_SHIFT)
++
++
++/*
++ . Bank Select Register:
++ .
++ . yyyy yyyy 0000 00xx
++ . xx = bank number
++ . yyyy yyyy = 0x33, for identification purposes.
++*/
++#define BANK_SELECT (14 << SMC_IO_SHIFT)
++
++
++// Transmit Control Register
++/* BANK 0 */
++#define TCR_REG SMC_REG(0x0000, 0)
++#define TCR_ENABLE 0x0001 // When 1 we can transmit
++#define TCR_LOOP 0x0002 // Controls output pin LBK
++#define TCR_FORCOL 0x0004 // When 1 will force a collision
++#define TCR_PAD_EN 0x0080 // When 1 will pad tx frames < 64 bytes w/0
++#define TCR_NOCRC 0x0100 // When 1 will not append CRC to tx frames
++#define TCR_MON_CSN 0x0400 // When 1 tx monitors carrier
++#define TCR_FDUPLX 0x0800 // When 1 enables full duplex operation
++#define TCR_STP_SQET 0x1000 // When 1 stops tx if Signal Quality Error
++#define TCR_EPH_LOOP 0x2000 // When 1 enables EPH block loopback
++#define TCR_SWFDUP 0x8000 // When 1 enables Switched Full Duplex mode
++
++#define TCR_CLEAR 0 /* do NOTHING */
++/* the default settings for the TCR register : */
++#define TCR_DEFAULT (TCR_ENABLE | TCR_PAD_EN)
++
++
++// EPH Status Register
++/* BANK 0 */
++#define EPH_STATUS_REG SMC_REG(0x0002, 0)
++#define ES_TX_SUC 0x0001 // Last TX was successful
++#define ES_SNGL_COL 0x0002 // Single collision detected for last tx
++#define ES_MUL_COL 0x0004 // Multiple collisions detected for last tx
++#define ES_LTX_MULT 0x0008 // Last tx was a multicast
++#define ES_16COL 0x0010 // 16 Collisions Reached
++#define ES_SQET 0x0020 // Signal Quality Error Test
++#define ES_LTXBRD 0x0040 // Last tx was a broadcast
++#define ES_TXDEFR 0x0080 // Transmit Deferred
++#define ES_LATCOL 0x0200 // Late collision detected on last tx
++#define ES_LOSTCARR 0x0400 // Lost Carrier Sense
++#define ES_EXC_DEF 0x0800 // Excessive Deferral
++#define ES_CTR_ROL 0x1000 // Counter Roll Over indication
++#define ES_LINK_OK 0x4000 // Driven by inverted value of nLNK pin
++#define ES_TXUNRN 0x8000 // Tx Underrun
++
++
++// Receive Control Register
++/* BANK 0 */
++#define RCR_REG SMC_REG(0x0004, 0)
++#define RCR_RX_ABORT 0x0001 // Set if a rx frame was aborted
++#define RCR_PRMS 0x0002 // Enable promiscuous mode
++#define RCR_ALMUL 0x0004 // When set accepts all multicast frames
++#define RCR_RXEN 0x0100 // IFF this is set, we can receive packets
++#define RCR_STRIP_CRC 0x0200 // When set strips CRC from rx packets
++#define RCR_ABORT_ENB 0x0200 // When set will abort rx on collision
++#define RCR_FILT_CAR 0x0400 // When set filters leading 12 bit s of carrier
++#define RCR_SOFTRST 0x8000 // resets the chip
++
++/* the normal settings for the RCR register : */
++#define RCR_DEFAULT (RCR_STRIP_CRC | RCR_RXEN)
++#define RCR_CLEAR 0x0 // set it to a base state
++
++
++// Counter Register
++/* BANK 0 */
++#define COUNTER_REG SMC_REG(0x0006, 0)
++
++
++// Memory Information Register
++/* BANK 0 */
++#define MIR_REG SMC_REG(0x0008, 0)
++
++
++// Receive/Phy Control Register
++/* BANK 0 */
++#define RPC_REG SMC_REG(0x000A, 0)
++#define RPC_SPEED 0x2000 // When 1 PHY is in 100Mbps mode.
++#define RPC_DPLX 0x1000 // When 1 PHY is in Full-Duplex Mode
++#define RPC_ANEG 0x0800 // When 1 PHY is in Auto-Negotiate Mode
++#define RPC_LSXA_SHFT 5 // Bits to shift LS2A,LS1A,LS0A to lsb
++#define RPC_LSXB_SHFT 2 // Bits to get LS2B,LS1B,LS0B to lsb
++#define RPC_LED_100_10 (0x00) // LED = 100Mbps OR's with 10Mbps link detect
++#define RPC_LED_RES (0x01) // LED = Reserved
++#define RPC_LED_10 (0x02) // LED = 10Mbps link detect
++#define RPC_LED_FD (0x03) // LED = Full Duplex Mode
++#define RPC_LED_TX_RX (0x04) // LED = TX or RX packet occurred
++#define RPC_LED_100 (0x05) // LED = 100Mbps link dectect
++#define RPC_LED_TX (0x06) // LED = TX packet occurred
++#define RPC_LED_RX (0x07) // LED = RX packet occurred
++#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
++
++
++/* Bank 0 0x0C is reserved */
++
++// Bank Select Register
++/* All Banks */
++#define BSR_REG 0x000E
++
++
++// Configuration Reg
++/* BANK 1 */
++#define CONFIG_REG SMC_REG(0x0000, 1)
++#define CONFIG_EXT_PHY 0x0200 // 1=external MII, 0=internal Phy
++#define CONFIG_GPCNTRL 0x0400 // Inverse value drives pin nCNTRL
++#define CONFIG_NO_WAIT 0x1000 // When 1 no extra wait states on ISA bus
++#define CONFIG_EPH_POWER_EN 0x8000 // When 0 EPH is placed into low power mode.
++
++// Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low
++#define CONFIG_DEFAULT (CONFIG_EPH_POWER_EN)
++
++
++// Base Address Register
++/* BANK 1 */
++#define BASE_REG SMC_REG(0x0002, 1)
++
++
++// Individual Address Registers
++/* BANK 1 */
++#define ADDR0_REG SMC_REG(0x0004, 1)
++#define ADDR1_REG SMC_REG(0x0006, 1)
++#define ADDR2_REG SMC_REG(0x0008, 1)
++
++
++// General Purpose Register
++/* BANK 1 */
++#define GP_REG SMC_REG(0x000A, 1)
++
++
++// Control Register
++/* BANK 1 */
++#define CTL_REG SMC_REG(0x000C, 1)
++#define CTL_RCV_BAD 0x4000 // When 1 bad CRC packets are received
++#define CTL_AUTO_RELEASE 0x0800 // When 1 tx pages are released automatically
++#define CTL_LE_ENABLE 0x0080 // When 1 enables Link Error interrupt
++#define CTL_CR_ENABLE 0x0040 // When 1 enables Counter Rollover interrupt
++#define CTL_TE_ENABLE 0x0020 // When 1 enables Transmit Error interrupt
++#define CTL_EEPROM_SELECT 0x0004 // Controls EEPROM reload & store
++#define CTL_RELOAD 0x0002 // When set reads EEPROM into registers
++#define CTL_STORE 0x0001 // When set stores registers into EEPROM
++
++
++// MMU Command Register
++/* BANK 2 */
++#define MMU_CMD_REG SMC_REG(0x0000, 2)
++#define MC_BUSY 1 // When 1 the last release has not completed
++#define MC_NOP (0<<5) // No Op
++#define MC_ALLOC (1<<5) // OR with number of 256 byte packets
++#define MC_RESET (2<<5) // Reset MMU to initial state
++#define MC_REMOVE (3<<5) // Remove the current rx packet
++#define MC_RELEASE (4<<5) // Remove and release the current rx packet
++#define MC_FREEPKT (5<<5) // Release packet in PNR register
++#define MC_ENQUEUE (6<<5) // Enqueue the packet for transmit
++#define MC_RSTTXFIFO (7<<5) // Reset the TX FIFOs
++
++
++// Packet Number Register
++/* BANK 2 */
++#define PN_REG SMC_REG(0x0002, 2)
++
++
++// Allocation Result Register
++/* BANK 2 */
++#define AR_REG SMC_REG(0x0003, 2)
++#define AR_FAILED 0x80 // Alocation Failed
++
++
++// TX FIFO Ports Register
++/* BANK 2 */
++#define TXFIFO_REG SMC_REG(0x0004, 2)
++#define TXFIFO_TEMPTY 0x80 // TX FIFO Empty
++
++// RX FIFO Ports Register
++/* BANK 2 */
++#define RXFIFO_REG SMC_REG(0x0005, 2)
++#define RXFIFO_REMPTY 0x80 // RX FIFO Empty
++
++#define FIFO_REG SMC_REG(0x0004, 2)
++
++// Pointer Register
++/* BANK 2 */
++#define PTR_REG SMC_REG(0x0006, 2)
++#define PTR_RCV 0x8000 // 1=Receive area, 0=Transmit area
++#define PTR_AUTOINC 0x4000 // Auto increment the pointer on each access
++#define PTR_READ 0x2000 // When 1 the operation is a read
++
++
++// Data Register
++/* BANK 2 */
++#define DATA_REG SMC_REG(0x0008, 2)
++
++
++// Interrupt Status/Acknowledge Register
++/* BANK 2 */
++#define INT_REG SMC_REG(0x000C, 2)
++
++
++// Interrupt Mask Register
++/* BANK 2 */
++#define IM_REG SMC_REG(0x000D, 2)
++#define IM_MDINT 0x80 // PHY MI Register 18 Interrupt
++#define IM_ERCV_INT 0x40 // Early Receive Interrupt
++#define IM_EPH_INT 0x20 // Set by Ethernet Protocol Handler section
++#define IM_RX_OVRN_INT 0x10 // Set by Receiver Overruns
++#define IM_ALLOC_INT 0x08 // Set when allocation request is completed
++#define IM_TX_EMPTY_INT 0x04 // Set if the TX FIFO goes empty
++#define IM_TX_INT 0x02 // Transmit Interrupt
++#define IM_RCV_INT 0x01 // Receive Interrupt
++
++
++// Multicast Table Registers
++/* BANK 3 */
++#define MCAST_REG1 SMC_REG(0x0000, 3)
++#define MCAST_REG2 SMC_REG(0x0002, 3)
++#define MCAST_REG3 SMC_REG(0x0004, 3)
++#define MCAST_REG4 SMC_REG(0x0006, 3)
++
++
++// Management Interface Register (MII)
++/* BANK 3 */
++#define MII_REG SMC_REG(0x0008, 3)
++#define MII_MSK_CRS100 0x4000 // Disables CRS100 detection during tx half dup
++#define MII_MDOE 0x0008 // MII Output Enable
++#define MII_MCLK 0x0004 // MII Clock, pin MDCLK
++#define MII_MDI 0x0002 // MII Input, pin MDI
++#define MII_MDO 0x0001 // MII Output, pin MDO
++
++
++// Revision Register
++/* BANK 3 */
++/* ( hi: chip id low: rev # ) */
++#define REV_REG SMC_REG(0x000A, 3)
++
++
++// Early RCV Register
++/* BANK 3 */
++/* this is NOT on SMC9192 */
++#define ERCV_REG SMC_REG(0x000C, 3)
++#define ERCV_RCV_DISCRD 0x0080 // When 1 discards a packet being received
++#define ERCV_THRESHOLD 0x001F // ERCV Threshold Mask
++
++
++// External Register
++/* BANK 7 */
++#define EXT_REG SMC_REG(0x0000, 7)
++
++
++#define CHIP_9192 3
++#define CHIP_9194 4
++#define CHIP_9195 5
++#define CHIP_9196 6
++#define CHIP_91100 7
++#define CHIP_91100FD 8
++#define CHIP_91111FD 9
++
++static const char * chip_ids[ 16 ] = {
++ NULL, NULL, NULL,
++ /* 3 */ "SMC91C90/91C92",
++ /* 4 */ "SMC91C94",
++ /* 5 */ "SMC91C95",
++ /* 6 */ "SMC91C96",
++ /* 7 */ "SMC91C100",
++ /* 8 */ "SMC91C100FD",
++ /* 9 */ "SMC91C11xFD",
++ NULL, NULL, NULL,
++ NULL, NULL, NULL};
++
++
++/*
++ . Transmit status bits
++*/
++#define TS_SUCCESS 0x0001
++#define TS_LOSTCAR 0x0400
++#define TS_LATCOL 0x0200
++#define TS_16COL 0x0010
++
++/*
++ . Receive status bits
++*/
++#define RS_ALGNERR 0x8000
++#define RS_BRODCAST 0x4000
++#define RS_BADCRC 0x2000
++#define RS_ODDFRAME 0x1000
++#define RS_TOOLONG 0x0800
++#define RS_TOOSHORT 0x0400
++#define RS_MULTICAST 0x0001
++#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
++
++
++// PHY Types
++enum {
++ PHY_LAN83C183 = 1, // LAN91C111 Internal PHY
++ PHY_LAN83C180
++};
++
++
++// PHY Register Addresses (LAN91C111 Internal PHY)
++
++// PHY Control Register
++#define PHY_CNTL_REG 0x00
++#define PHY_CNTL_RST 0x8000 // 1=PHY Reset
++#define PHY_CNTL_LPBK 0x4000 // 1=PHY Loopback
++#define PHY_CNTL_SPEED 0x2000 // 1=100Mbps, 0=10Mpbs
++#define PHY_CNTL_ANEG_EN 0x1000 // 1=Enable Auto negotiation
++#define PHY_CNTL_PDN 0x0800 // 1=PHY Power Down mode
++#define PHY_CNTL_MII_DIS 0x0400 // 1=MII 4 bit interface disabled
++#define PHY_CNTL_ANEG_RST 0x0200 // 1=Reset Auto negotiate
++#define PHY_CNTL_DPLX 0x0100 // 1=Full Duplex, 0=Half Duplex
++#define PHY_CNTL_COLTST 0x0080 // 1= MII Colision Test
++
++// PHY Status Register
++#define PHY_STAT_REG 0x01
++#define PHY_STAT_CAP_T4 0x8000 // 1=100Base-T4 capable
++#define PHY_STAT_CAP_TXF 0x4000 // 1=100Base-X full duplex capable
++#define PHY_STAT_CAP_TXH 0x2000 // 1=100Base-X half duplex capable
++#define PHY_STAT_CAP_TF 0x1000 // 1=10Mbps full duplex capable
++#define PHY_STAT_CAP_TH 0x0800 // 1=10Mbps half duplex capable
++#define PHY_STAT_CAP_SUPR 0x0040 // 1=recv mgmt frames with not preamble
++#define PHY_STAT_ANEG_ACK 0x0020 // 1=ANEG has completed
++#define PHY_STAT_REM_FLT 0x0010 // 1=Remote Fault detected
++#define PHY_STAT_CAP_ANEG 0x0008 // 1=Auto negotiate capable
++#define PHY_STAT_LINK 0x0004 // 1=valid link
++#define PHY_STAT_JAB 0x0002 // 1=10Mbps jabber condition
++#define PHY_STAT_EXREG 0x0001 // 1=extended registers implemented
++
++// PHY Identifier Registers
++#define PHY_ID1_REG 0x02 // PHY Identifier 1
++#define PHY_ID2_REG 0x03 // PHY Identifier 2
++
++// PHY Auto-Negotiation Advertisement Register
++#define PHY_AD_REG 0x04
++#define PHY_AD_NP 0x8000 // 1=PHY requests exchange of Next Page
++#define PHY_AD_ACK 0x4000 // 1=got link code word from remote
++#define PHY_AD_RF 0x2000 // 1=advertise remote fault
++#define PHY_AD_T4 0x0200 // 1=PHY is capable of 100Base-T4
++#define PHY_AD_TX_FDX 0x0100 // 1=PHY is capable of 100Base-TX FDPLX
++#define PHY_AD_TX_HDX 0x0080 // 1=PHY is capable of 100Base-TX HDPLX
++#define PHY_AD_10_FDX 0x0040 // 1=PHY is capable of 10Base-T FDPLX
++#define PHY_AD_10_HDX 0x0020 // 1=PHY is capable of 10Base-T HDPLX
++#define PHY_AD_CSMA 0x0001 // 1=PHY is capable of 802.3 CMSA
++
++// PHY Auto-negotiation Remote End Capability Register
++#define PHY_RMT_REG 0x05
++// Uses same bit definitions as PHY_AD_REG
++
++// PHY Configuration Register 1
++#define PHY_CFG1_REG 0x10
++#define PHY_CFG1_LNKDIS 0x8000 // 1=Rx Link Detect Function disabled
++#define PHY_CFG1_XMTDIS 0x4000 // 1=TP Transmitter Disabled
++#define PHY_CFG1_XMTPDN 0x2000 // 1=TP Transmitter Powered Down
++#define PHY_CFG1_BYPSCR 0x0400 // 1=Bypass scrambler/descrambler
++#define PHY_CFG1_UNSCDS 0x0200 // 1=Unscramble Idle Reception Disable
++#define PHY_CFG1_EQLZR 0x0100 // 1=Rx Equalizer Disabled
++#define PHY_CFG1_CABLE 0x0080 // 1=STP(150ohm), 0=UTP(100ohm)
++#define PHY_CFG1_RLVL0 0x0040 // 1=Rx Squelch level reduced by 4.5db
++#define PHY_CFG1_TLVL_SHIFT 2 // Transmit Output Level Adjust
++#define PHY_CFG1_TLVL_MASK 0x003C
++#define PHY_CFG1_TRF_MASK 0x0003 // Transmitter Rise/Fall time
++
++
++// PHY Configuration Register 2
++#define PHY_CFG2_REG 0x11
++#define PHY_CFG2_APOLDIS 0x0020 // 1=Auto Polarity Correction disabled
++#define PHY_CFG2_JABDIS 0x0010 // 1=Jabber disabled
++#define PHY_CFG2_MREG 0x0008 // 1=Multiple register access (MII mgt)
++#define PHY_CFG2_INTMDIO 0x0004 // 1=Interrupt signaled with MDIO pulseo
++
++// PHY Status Output (and Interrupt status) Register
++#define PHY_INT_REG 0x12 // Status Output (Interrupt Status)
++#define PHY_INT_INT 0x8000 // 1=bits have changed since last read
++#define PHY_INT_LNKFAIL 0x4000 // 1=Link Not detected
++#define PHY_INT_LOSSSYNC 0x2000 // 1=Descrambler has lost sync
++#define PHY_INT_CWRD 0x1000 // 1=Invalid 4B5B code detected on rx
++#define PHY_INT_SSD 0x0800 // 1=No Start Of Stream detected on rx
++#define PHY_INT_ESD 0x0400 // 1=No End Of Stream detected on rx
++#define PHY_INT_RPOL 0x0200 // 1=Reverse Polarity detected
++#define PHY_INT_JAB 0x0100 // 1=Jabber detected
++#define PHY_INT_SPDDET 0x0080 // 1=100Base-TX mode, 0=10Base-T mode
++#define PHY_INT_DPLXDET 0x0040 // 1=Device in Full Duplex
++
++// PHY Interrupt/Status Mask Register
++#define PHY_MASK_REG 0x13 // Interrupt Mask
++// Uses the same bit definitions as PHY_INT_REG
++
++
++/*
++ * SMC91C96 ethernet config and status registers.
++ * These are in the "attribute" space.
++ */
++#define ECOR 0x8000
++#define ECOR_RESET 0x80
++#define ECOR_LEVEL_IRQ 0x40
++#define ECOR_WR_ATTRIB 0x04
++#define ECOR_ENABLE 0x01
++
++#define ECSR 0x8002
++#define ECSR_IOIS8 0x20
++#define ECSR_PWRDWN 0x04
++#define ECSR_INT 0x02
++
++
++/*
++ * Macros to abstract register access according to the data bus
++ * capabilities. Please try to use those and not the in/out primitives.
++ * Note: the following macros do *not* select the bank -- this must
++ * be done separately as needed in the main code. The SMC_REG() macro
++ * only uses the bank argument for debugging purposes.
++ */
++
++#if SMC_DEBUG > 0
++#define SMC_REG(reg, bank) \
++ ({ \
++ int __b = SMC_CURRENT_BANK(); \
++ if ((__b & ~0xf0) != (0x3300 | bank)) { \
++ printk( "%s: bank reg screwed (0x%04x)\n", \
++ CARDNAME, __b ); \
++ BUG(); \
++ } \
++ reg<<SMC_IO_SHIFT; \
++ })
++#else
++#define SMC_REG(reg, bank) (reg<<SMC_IO_SHIFT)
++#endif
++
++#if SMC_CAN_USE_8BIT
++#define SMC_GET_PN() SMC_inb( ioaddr, PN_REG )
++#define SMC_SET_PN(x) SMC_outb( x, ioaddr, PN_REG )
++#define SMC_GET_AR() SMC_inb( ioaddr, AR_REG )
++#define SMC_GET_TXFIFO() SMC_inb( ioaddr, TXFIFO_REG )
++#define SMC_GET_RXFIFO() SMC_inb( ioaddr, RXFIFO_REG )
++#define SMC_GET_INT() SMC_inb( ioaddr, INT_REG )
++#define SMC_ACK_INT(x) SMC_outb( x, ioaddr, INT_REG )
++#define SMC_GET_INT_MASK() SMC_inb( ioaddr, IM_REG )
++#define SMC_SET_INT_MASK(x) SMC_outb( x, ioaddr, IM_REG )
++#else
++#define SMC_GET_PN() (SMC_inw( ioaddr, PN_REG ) & 0xFF)
++#define SMC_SET_PN(x) SMC_outw( x, ioaddr, PN_REG )
++#define SMC_GET_AR() (SMC_inw( ioaddr, PN_REG ) >> 8)
++#define SMC_GET_TXFIFO() (SMC_inw( ioaddr, TXFIFO_REG ) & 0xFF)
++#define SMC_GET_RXFIFO() (SMC_inw( ioaddr, TXFIFO_REG ) >> 8)
++#define SMC_GET_INT() (SMC_inw( ioaddr, INT_REG ) & 0xFF)
++#define SMC_ACK_INT(x) \
++ do { \
++ unsigned long __flags; \
++ int __mask; \
++ local_irq_save(__flags); \
++ __mask = SMC_inw( ioaddr, INT_REG ) & ~0xff; \
++ SMC_outw( __mask | (x), ioaddr, INT_REG ); \
++ local_irq_restore(__flags); \
++ } while (0)
++#define SMC_GET_INT_MASK() (SMC_inw( ioaddr, INT_REG ) >> 8)
++#define SMC_SET_INT_MASK(x) SMC_outw( (x) << 8, ioaddr, INT_REG )
++#endif
++
++#define SMC_CURRENT_BANK() SMC_inw( ioaddr, BANK_SELECT )
++#define SMC_SELECT_BANK(x) SMC_outw( x, ioaddr, BANK_SELECT )
++#define SMC_GET_BASE() SMC_inw( ioaddr, BASE_REG )
++#define SMC_SET_BASE(x) SMC_outw( x, ioaddr, BASE_REG )
++#define SMC_GET_CONFIG() SMC_inw( ioaddr, CONFIG_REG )
++#define SMC_SET_CONFIG(x) SMC_outw( x, ioaddr, CONFIG_REG )
++#define SMC_GET_COUNTER() SMC_inw( ioaddr, COUNTER_REG )
++#define SMC_GET_CTL() SMC_inw( ioaddr, CTL_REG )
++#define SMC_SET_CTL(x) SMC_outw( x, ioaddr, CTL_REG )
++#define SMC_GET_MII() SMC_inw( ioaddr, MII_REG )
++#define SMC_SET_MII(x) SMC_outw( x, ioaddr, MII_REG )
++#define SMC_GET_MIR() SMC_inw( ioaddr, MIR_REG )
++#define SMC_SET_MIR(x) SMC_outw( x, ioaddr, MIR_REG )
++#define SMC_GET_MMU_CMD() SMC_inw( ioaddr, MMU_CMD_REG )
++#define SMC_SET_MMU_CMD(x) SMC_outw( x, ioaddr, MMU_CMD_REG )
++#define SMC_GET_FIFO() SMC_inw( ioaddr, FIFO_REG )
++#define SMC_GET_PTR() SMC_inw( ioaddr, PTR_REG )
++#define SMC_SET_PTR(x) SMC_outw( x, ioaddr, PTR_REG )
++#define SMC_GET_RCR() SMC_inw( ioaddr, RCR_REG )
++#define SMC_SET_RCR(x) SMC_outw( x, ioaddr, RCR_REG )
++#define SMC_GET_REV() SMC_inw( ioaddr, REV_REG )
++#define SMC_GET_RPC() SMC_inw( ioaddr, RPC_REG )
++#define SMC_SET_RPC(x) SMC_outw( x, ioaddr, RPC_REG )
++#define SMC_GET_TCR() SMC_inw( ioaddr, TCR_REG )
++#define SMC_SET_TCR(x) SMC_outw( x, ioaddr, TCR_REG )
++
++#ifndef SMC_GET_MAC_ADDR
++#define SMC_GET_MAC_ADDR(addr) \
++ do { \
++ unsigned int __v; \
++ __v = SMC_inw( ioaddr, ADDR0_REG ); \
++ addr[0] = __v; addr[1] = __v >> 8; \
++ __v = SMC_inw( ioaddr, ADDR1_REG ); \
++ addr[2] = __v; addr[3] = __v >> 8; \
++ __v = SMC_inw( ioaddr, ADDR2_REG ); \
++ addr[4] = __v; addr[5] = __v >> 8; \
++ } while (0)
++#endif
++
++#define SMC_SET_MAC_ADDR(addr) \
++ do { \
++ SMC_outw( addr[0]|(addr[1] << 8), ioaddr, ADDR0_REG ); \
++ SMC_outw( addr[2]|(addr[3] << 8), ioaddr, ADDR1_REG ); \
++ SMC_outw( addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG ); \
++ } while (0)
++
++#define SMC_CLEAR_MCAST() \
++ do { \
++ SMC_outw( 0, ioaddr, MCAST_REG1 ); \
++ SMC_outw( 0, ioaddr, MCAST_REG2 ); \
++ SMC_outw( 0, ioaddr, MCAST_REG3 ); \
++ SMC_outw( 0, ioaddr, MCAST_REG4 ); \
++ } while (0)
++#define SMC_SET_MCAST(x) \
++ do { \
++ unsigned char *mt = (x); \
++ SMC_outw( mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1 ); \
++ SMC_outw( mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2 ); \
++ SMC_outw( mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3 ); \
++ SMC_outw( mt[6] | (mt[7] << 8), ioaddr, MCAST_REG4 ); \
++ } while (0)
++
++#if SMC_CAN_USE_32BIT
++/*
++ * Some setups just can't write 8 or 16 bits reliably when not aligned
++ * to a 32 bit boundary. I tell you that exists!
++ * We do the ones that can have their low parts written to 0 here.
++ */
++#undef SMC_SELECT_BANK
++#define SMC_SELECT_BANK(x) SMC_outl( (x)<<16, ioaddr, 12<<SMC_IO_SHIFT )
++#undef SMC_SET_RPC
++#define SMC_SET_RPC(x) SMC_outl( (x)<<16, ioaddr, SMC_REG(8, 0) )
++#undef SMC_SET_PN
++#define SMC_SET_PN(x) SMC_outl( (x)<<16, ioaddr, SMC_REG(0, 2) )
++#undef SMC_SET_PTR
++#define SMC_SET_PTR(x) SMC_outl( (x)<<16, ioaddr, SMC_REG(4, 2) )
++#endif
++
++#if SMC_CAN_USE_32BIT
++#define SMC_PUT_PKT_HDR(status, length) \
++ SMC_outl( (status) | (length) << 16, ioaddr, DATA_REG )
++#define SMC_GET_PKT_HDR(status, length) \
++ do { \
++ unsigned int __val = SMC_inl( ioaddr, DATA_REG ); \
++ (status) = __val & 0xffff; \
++ (length) = __val >> 16; \
++ } while (0)
++#else
++#define SMC_PUT_PKT_HDR(status, length) \
++ do { \
++ SMC_outw( status, ioaddr, DATA_REG ); \
++ SMC_outw( length, ioaddr, DATA_REG ); \
++ } while (0)
++#define SMC_GET_PKT_HDR(status, length) \
++ do { \
++ (status) = SMC_inw( ioaddr, DATA_REG ); \
++ (length) = SMC_inw( ioaddr, DATA_REG ); \
++ } while (0)
++#endif
++
++#if SMC_CAN_USE_32BIT
++#define SMC_PUSH_DATA(p, l) \
++ do { \
++ char *__ptr = (p); \
++ int __len = (l); \
++ if (__len >= 2 && (long)__ptr & 2) { \
++ __len -= 2; \
++ SMC_outw( *((u16 *)__ptr)++, ioaddr, DATA_REG );\
++ } \
++ SMC_outsl( ioaddr, DATA_REG, __ptr, __len >> 2); \
++ if (__len & 2) { \
++ __ptr += (__len & ~3); \
++ SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG ); \
++ } \
++ } while (0)
++#define SMC_PULL_DATA(p, l) \
++ do { \
++ char *__ptr = (p); \
++ int __len = (l); \
++ if ((long)__ptr & 2) { \
++ /* \
++ * We want 32bit alignment here. \
++ * Since some buses perform a full 32bit \
++ * fetch even for 16bit data we can't use \
++ * SMC_inw() here. Back both source (on chip \
++ * and destination) pointers of 2 bytes. \
++ */ \
++ (long)__ptr &= ~2; \
++ __len += 2; \
++ SMC_SET_PTR( 2|PTR_READ|PTR_RCV|PTR_AUTOINC ); \
++ } \
++ __len += 2; \
++ SMC_insl( ioaddr, DATA_REG, __ptr, __len >> 2); \
++ } while (0)
++#elif SMC_CAN_USE_16BIT
++#define SMC_PUSH_DATA(p, l) SMC_outsw( ioaddr, DATA_REG, p, (l) >> 1 )
++#define SMC_PULL_DATA(p, l) SMC_insw ( ioaddr, DATA_REG, p, (l) >> 1 )
++#elif SMC_CAN_USE_8BIT
++#define SMC_PUSH_DATA(p, l) SMC_outsb( ioaddr, DATA_REG, p, l )
++#define SMC_PULL_DATA(p, l) SMC_insb ( ioaddr, DATA_REG, p, l )
++#endif
++
++#if ! SMC_CAN_USE_16BIT
++#define SMC_outw(x, ioaddr, reg) \
++ do { \
++ unsigned int __val16 = (x); \
++ SMC_outb( __val16, ioaddr, reg ); \
++ SMC_outb( __val16 >> 8, ioaddr, reg + 1 ); \
++ } while (0)
++#define SMC_inw(ioaddr, reg) \
++ ({ \
++ unsigned int __val16; \
++ __val16 = SMC_inb( ioaddr, reg ); \
++ __val16 |= SMC_inb( ioaddr, reg + 1 ) << 8; \
++ __val16; \
++ })
++#endif
++
++
++#endif /* _SMC91X_H_ */
+--- linux-2.4.27/drivers/pcmcia/Config.in~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/pcmcia/Config.in
+@@ -45,6 +45,7 @@
+ if [ "$CONFIG_ARM" = "y" ]; then
+ dep_tristate ' CLPS6700 support' CONFIG_PCMCIA_CLPS6700 $CONFIG_ARCH_CLPS711X $CONFIG_PCMCIA
+ dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
++ dep_tristate ' PXA250/210 support' CONFIG_PCMCIA_PXA $CONFIG_ARCH_PXA $CONFIG_PCMCIA
+ fi
+
+ endmenu
+--- linux-2.4.27/drivers/pcmcia/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/pcmcia/Makefile
+@@ -94,6 +94,11 @@
+
+ obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o
+
++subdir-$(CONFIG_PCMCIA_PXA) += pxa
++ifeq ($(CONFIG_PCMCIA_PXA),y)
++ obj-y += pxa/pxa_cs.o
++endif
++
+ include $(TOPDIR)/Rules.make
+
+ pcmcia_core.o: $(pcmcia_core-objs)
+--- /dev/null
++++ linux-2.4.27/drivers/pcmcia/pxa/Makefile
+@@ -0,0 +1,18 @@
++#
++# Makefile for the Intel PXA250/210 PCMCIA driver
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++O_TARGET := pxa_cs.o
++
++obj-y := pxa.o
++obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
++obj-$(CONFIG_ARCH_PXA_IDP) += pxa_idp.o
++obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o
++obj-$(CONFIG_ARCH_PXA_CERF) += ../sa1100_cerf.o
++
++obj-m := $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+--- /dev/null
++++ linux-2.4.27/drivers/pcmcia/pxa/lubbock.c
+@@ -0,0 +1,329 @@
++/*
++ * linux/drivers/pcmcia/pxa/lubbock.c
++ *
++ * Author: George Davis
++ * Created: Jan 10, 2002
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c
++ *
++ * Lubbock PCMCIA specific routines.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++
++#include <pcmcia/ss.h>
++
++#include <asm/delay.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/arch/pcmcia.h>
++#include <asm/hardware/sa1111.h>
++
++/*
++ * I'd really like to move the INTPOL stuff to arch/arm/mach-sa1100/sa1111.c
++ * ... and maybe even arch/arm/mach-pxa/sa1111.c now too! : )
++ */
++#define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START))
++#define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32))
++
++static int lubbock_pcmcia_init(struct pcmcia_init *init){
++ int return_val=0;
++
++ /* Set PCMCIA Socket 0 power to standby mode.
++ */
++ PA_DWR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3));
++
++ /* Set GPIO_A<3:0> to be outputs for PCMCIA (socket 0) power controller.
++ * Note that this is done only after first initializing GPIO_A<3:0>
++ * output state above to be certain that we drive signals to the same
++ * state as the pull-downs connected to these lines. The pull-downs are
++ * req'd to make sure PCMCIA power is OFF until we can get around to
++ * setting up the GPIO_A<3:0> state and direction.
++ */
++ PA_DDR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3));
++
++ /* Set CF Socket 1 power to standby mode. */
++ LUB_MISC_WR &= ~(GPIO_bit(15) | GPIO_bit(14));
++
++ INTPOL1 |= SA1111_IRQMASK_HI(S0_READY_NINT) |
++ SA1111_IRQMASK_HI(S1_READY_NINT) |
++ SA1111_IRQMASK_HI(S0_CD_VALID) |
++ SA1111_IRQMASK_HI(S1_CD_VALID) |
++ SA1111_IRQMASK_HI(S0_BVD1_STSCHG) |
++ SA1111_IRQMASK_HI(S1_BVD1_STSCHG);
++
++#warning what if a request_irq fails?
++ return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
++ "Lubbock PCMCIA (0) CD", NULL);
++ return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
++ "Lubbock CF (1) CD", NULL);
++ return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
++ "Lubbock PCMCIA (0) BVD1", NULL);
++ return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
++ "Lubbock CF (1) BVD1", NULL);
++
++ return (return_val<0) ? -1 : 2;
++}
++
++static int lubbock_pcmcia_shutdown(void){
++
++ free_irq(S0_CD_VALID, NULL);
++ free_irq(S1_CD_VALID, NULL);
++ free_irq(S0_BVD1_STSCHG, NULL);
++ free_irq(S1_BVD1_STSCHG, NULL);
++
++ INTPOL1 &= ~(SA1111_IRQMASK_HI(S0_CD_VALID) |
++ SA1111_IRQMASK_HI(S1_CD_VALID) |
++ SA1111_IRQMASK_HI(S0_BVD1_STSCHG) |
++ SA1111_IRQMASK_HI(S1_BVD1_STSCHG));
++
++ return 0;
++}
++
++static int lubbock_pcmcia_socket_state(struct pcmcia_state_array
++ *state_array){
++ unsigned long status;
++ int return_val=1;
++
++ if(state_array->size<2) return -1;
++
++ memset(state_array->state, 0,
++ (state_array->size)*sizeof(struct pcmcia_state));
++
++ status=PCSR;
++
++ state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
++
++ state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
++
++ state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
++
++ state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
++
++ state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
++
++ state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
++
++ state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
++
++ state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
++
++ state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
++
++ state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
++
++ state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
++
++ state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
++
++ state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
++
++ state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
++
++ return return_val;
++}
++
++static int lubbock_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
++
++ switch(info->sock){
++ case 0:
++ info->irq=S0_READY_NINT;
++ break;
++
++ case 1:
++ info->irq=S1_READY_NINT;
++ break;
++
++ default:
++ return -1;
++ }
++
++ return 0;
++}
++
++static int
++lubbock_pcmcia_configure_socket(unsigned int sock, socket_state_t *state)
++{
++ unsigned long flags, pccr, gpio, misc_wr, status;
++ int ret=1;
++
++ local_irq_save(flags);
++
++ pccr=PCCR;
++ gpio=PA_DWR;
++ misc_wr = LUB_MISC_WR;
++
++ /* Lubbock uses the Maxim MAX1602, with the following connections:
++ *
++ * Socket 0 (PCMCIA):
++ * MAX1602 Lubbock Register
++ * Pin Signal
++ * ----- ------- ----------------------
++ * A0VPP S0_PWR0 SA-1111 GPIO A<0>
++ * A1VPP S0_PWR1 SA-1111 GPIO A<1>
++ * A0VCC S0_PWR2 SA-1111 GPIO A<2>
++ * A1VCC S0_PWR3 SA-1111 GPIO A<3>
++ * VX VCC
++ * VY +3.3V
++ * 12IN +12V
++ * CODE +3.3V Cirrus Code, CODE = High (VY)
++ *
++ * Socket 1 (CF):
++ * MAX1602 Lubbock Register
++ * Pin Signal
++ * ----- ------- ----------------------
++ * A0VPP GND VPP is not connected
++ * A1VPP GND VPP is not connected
++ * A0VCC S1_PWR0 MISC_WR<14>
++ * A1VCC S1_PWR0 MISC_WR<15>
++ * VX VCC
++ * VY +3.3V
++ * 12IN GND VPP is not connected
++ * CODE +3.3V Cirrus Code, CODE = High (VY)
++ *
++ */
++
++again:
++ switch(sock){
++ case 0:
++
++ switch(state->Vcc){
++ case 0:
++ pccr = (pccr & ~PCCR_S0_FLT);
++ gpio &= ~(GPIO_bit(2) | GPIO_bit(3));
++ break;
++
++ case 33:
++ pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
++ gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(3);
++ break;
++
++ case 50:
++ pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
++ gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2);
++ break;
++
++ default:
++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, state->Vcc);
++ ret = -1;
++ break;
++ }
++
++ switch(state->Vpp){
++ case 0:
++ gpio &= ~(GPIO_bit(0) | GPIO_bit(1));
++ break;
++
++ case 120:
++ gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(1);
++ break;
++
++ default:
++ /* REVISIT: I'm not sure about this? Is this correct?
++ Is it always safe or do we have potential problems
++ with bogus combinations of Vcc and Vpp settings? */
++ if(state->Vpp == state->Vcc)
++ gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(0);
++ else {
++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, state->Vpp);
++ ret = -1;
++ break;
++ }
++ }
++
++ pccr = (state->flags&SS_RESET) ? (pccr|PCCR_S0_RST) : (pccr&~PCCR_S0_RST);
++
++ break;
++
++ case 1:
++ switch(state->Vcc){
++ case 0:
++ pccr = (pccr & ~PCCR_S1_FLT);
++ misc_wr &= ~((1 << 15) | (1 << 14));
++ break;
++
++ case 33:
++ pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
++ misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14);
++ gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2);
++ break;
++
++ case 50:
++ pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
++ misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14);
++ break;
++
++ default:
++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, state->Vcc);
++ ret = -1;
++ break;
++ }
++
++ if(state->Vpp!=state->Vcc && state->Vpp!=0){
++ printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, state->Vpp);
++ ret = -1;
++ break;
++ }
++
++ pccr = (state->flags&SS_RESET) ? (pccr|PCCR_S1_RST) : (pccr&~PCCR_S1_RST);
++
++ break;
++
++ default:
++ ret = -1;
++ }
++
++ if (ret >= 0) {
++ PCCR = pccr;
++ LUB_MISC_WR = misc_wr;
++ PA_DWR = gpio;
++ }
++
++ if (ret > 0) {
++ ret = 0;
++ /*
++ * HACK ALERT:
++ * We can't sense the voltage properly on Lubbock before actually
++ * applying some power to the socket (catch 22).
++ * Resense the socket Voltage Sense pins after applying socket power.
++ */
++ if (sock == 0)
++ status = PCSR & (PCSR_S0_VS1 | PCSR_S0_VS2);
++ else
++ status = PCSR & (PCSR_S1_VS1 | PCSR_S1_VS2);
++
++ if ((status == (PCSR_S0_VS1 | PCSR_S0_VS2)) && (state->Vcc == 33)) {
++ /* Switch to 5V, Configure socket 0 with 5V voltage */
++ PA_DWR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3));
++ PA_DDR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3));
++ state->Vcc = 50;
++ state->Vpp = 50;
++ goto again;
++ }
++ if ((status == (PCSR_S1_VS1 | PCSR_S1_VS2)) && (state->Vcc == 33)) {
++ /* Switch to 5V, Configure socket 1 with 5V voltage */
++ LUB_MISC_WR &= ~((1 << 15) | (1 << 14));
++ state->Vcc = 50;
++ state->Vpp = 50;
++ goto again;
++ }
++ }
++
++ local_irq_restore(flags);
++ return ret;
++}
++
++struct pcmcia_low_level lubbock_pcmcia_ops = {
++ lubbock_pcmcia_init,
++ lubbock_pcmcia_shutdown,
++ lubbock_pcmcia_socket_state,
++ lubbock_pcmcia_get_irq_info,
++ lubbock_pcmcia_configure_socket
++};
+--- /dev/null
++++ linux-2.4.27/drivers/pcmcia/pxa/pxa.c
+@@ -0,0 +1,1247 @@
++/*
++ * linux/drivers/pcmcia/pxa/pxa.c
++ *
++ * Author: George Davis
++ * Created: Jan 10, 2002
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Originally based upon linux/drivers/pcmcia/sa1100_generic.c
++ *
++ */
++
++/*======================================================================
++
++ Device driver for the PCMCIA control functionality of Intel
++ PXA250/210 microprocessors.
++
++ The contents of this file are subject to the Mozilla Public
++ License Version 1.1 (the "License"); you may not use this file
++ except in compliance with the License. You may obtain a copy of
++ the License at http://www.mozilla.org/MPL/
++
++ Software distributed under the License is distributed on an "AS
++ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ implied. See the License for the specific language governing
++ rights and limitations under the License.
++
++ The initial developer of the original code is John G. Dorsey
++ <john+@cs.cmu.edu>. Portions created by John G. Dorsey are
++ Copyright (C) 1999 John G. Dorsey. All Rights Reserved.
++
++ Alternatively, the contents of this file may be used under the
++ terms of the GNU Public License version 2 (the "GPL"), in which
++ case the provisions of the GPL are applicable instead of the
++ above. If you wish to allow the use of your version of this file
++ only under the terms of the GPL and not to allow others to use
++ your version of this file under the MPL, indicate your decision
++ by deleting the provisions above and replace them with the notice
++ and other provisions required by the GPL. If you do not delete
++ the provisions above, a recipient may use your version of this
++ file under either the MPL or the GPL.
++
++======================================================================*/
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/config.h>
++#include <linux/cpufreq.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/kernel.h>
++#include <linux/tqueue.h>
++#include <linux/timer.h>
++#include <linux/mm.h>
++#include <linux/notifier.h>
++#include <linux/proc_fs.h>
++#include <linux/version.h>
++#include <linux/cpufreq.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/ss.h>
++#include <pcmcia/bus_ops.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/arch/lubbock.h>
++
++#include "pxa.h"
++
++#ifdef PCMCIA_DEBUG
++static int pc_debug;
++#endif
++
++MODULE_AUTHOR("George Davis <davis_g@mvista.com>");
++MODULE_DESCRIPTION("Linux PCMCIA Card Services: PXA250/210 Socket Controller");
++
++/* This structure maintains housekeeping state for each socket, such
++ * as the last known values of the card detect pins, or the Card Services
++ * callback value associated with the socket:
++ */
++static struct pxa_pcmcia_socket
++pxa_pcmcia_socket[PXA_PCMCIA_MAX_SOCK];
++
++static int pxa_pcmcia_socket_count;
++
++
++/* Returned by the low-level PCMCIA interface: */
++static struct pcmcia_low_level *pcmcia_low_level;
++
++/* Event poll timer structure */
++static struct timer_list poll_timer;
++
++
++/* Prototypes for routines which are used internally: */
++
++static int pxa_pcmcia_driver_init(void);
++static void pxa_pcmcia_driver_shutdown(void);
++static void pxa_pcmcia_task_handler(void *data);
++static void pxa_pcmcia_poll_event(unsigned long data);
++static void pxa_pcmcia_interrupt(int irq, void *dev,
++ struct pt_regs *regs);
++static struct tq_struct pxa_pcmcia_task;
++
++#ifdef CONFIG_PROC_FS
++static int pxa_pcmcia_proc_status(char *buf, char **start, off_t pos,
++ int count, int *eof, void *data);
++#endif
++
++
++/* Prototypes for operations which are exported to the
++ * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core:
++ */
++
++static int pxa_pcmcia_init(unsigned int sock);
++static int pxa_pcmcia_suspend(unsigned int sock);
++static int pxa_pcmcia_register_callback(unsigned int sock,
++ void (*handler)(void *,
++ unsigned int),
++ void *info);
++static int pxa_pcmcia_inquire_socket(unsigned int sock,
++ socket_cap_t *cap);
++static int pxa_pcmcia_get_status(unsigned int sock, u_int *value);
++static int pxa_pcmcia_get_socket(unsigned int sock,
++ socket_state_t *state);
++static int pxa_pcmcia_set_socket(unsigned int sock,
++ socket_state_t *state);
++static int pxa_pcmcia_get_io_map(unsigned int sock,
++ struct pccard_io_map *io);
++static int pxa_pcmcia_set_io_map(unsigned int sock,
++ struct pccard_io_map *io);
++static int pxa_pcmcia_get_mem_map(unsigned int sock,
++ struct pccard_mem_map *mem);
++static int pxa_pcmcia_set_mem_map(unsigned int sock,
++ struct pccard_mem_map *mem);
++#ifdef CONFIG_PROC_FS
++static void pxa_pcmcia_proc_setup(unsigned int sock,
++ struct proc_dir_entry *base);
++#endif
++
++static struct pccard_operations pxa_pcmcia_operations = {
++ pxa_pcmcia_init,
++ pxa_pcmcia_suspend,
++ pxa_pcmcia_register_callback,
++ pxa_pcmcia_inquire_socket,
++ pxa_pcmcia_get_status,
++ pxa_pcmcia_get_socket,
++ pxa_pcmcia_set_socket,
++ pxa_pcmcia_get_io_map,
++ pxa_pcmcia_set_io_map,
++ pxa_pcmcia_get_mem_map,
++ pxa_pcmcia_set_mem_map,
++#ifdef CONFIG_PROC_FS
++ pxa_pcmcia_proc_setup
++#endif
++};
++
++#ifdef CONFIG_CPU_FREQ
++/* forward declaration */
++static struct notifier_block pxa_pcmcia_notifier_block;
++#endif
++
++
++/* pxa_pcmcia_driver_init()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ *
++ * This routine performs a basic sanity check to ensure that this
++ * kernel has been built with the appropriate board-specific low-level
++ * PCMCIA support, performs low-level PCMCIA initialization, registers
++ * this socket driver with Card Services, and then spawns the daemon
++ * thread which is the real workhorse of the socket driver.
++ *
++ * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
++ * on the low-level kernel interface.
++ *
++ * Returns: 0 on success, -1 on error
++ */
++static int __init pxa_pcmcia_driver_init(void){
++ servinfo_t info;
++ struct pcmcia_init pcmcia_init;
++ struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK];
++ struct pcmcia_state_array state_array;
++ unsigned int i, clock;
++ unsigned long mecr;
++
++ printk(KERN_INFO "Intel PXA250/210 PCMCIA (CS release %s)\n", CS_RELEASE);
++
++ CardServices(GetCardServicesInfo, &info);
++
++ if(info.Revision!=CS_RELEASE_CODE){
++ printk(KERN_ERR "Card Services release codes do not match\n");
++ return -1;
++ }
++
++ /* Setup GPIOs for PCMCIA/CF alternate function mode.
++ *
++ * It would be nice if set_GPIO_mode included support
++ * for driving GPIO outputs to default high/low state
++ * before programming GPIOs as outputs. Setting GPIO
++ * outputs to default high/low state via GPSR/GPCR
++ * before defining them as outputs should reduce
++ * the possibility of glitching outputs during GPIO
++ * setup. This of course assumes external terminators
++ * are present to hold GPIOs in a defined state.
++ *
++ * In the meantime, setup default state of GPIO
++ * outputs before we enable them as outputs.
++ */
++
++ GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
++ GPIO_bit(GPIO49_nPWE) |
++ GPIO_bit(GPIO50_nPIOR) |
++ GPIO_bit(GPIO51_nPIOW) |
++ GPIO_bit(GPIO52_nPCE_1) |
++ GPIO_bit(GPIO53_nPCE_2);
++
++ set_GPIO_mode(GPIO48_nPOE_MD);
++ set_GPIO_mode(GPIO49_nPWE_MD);
++ set_GPIO_mode(GPIO50_nPIOR_MD);
++ set_GPIO_mode(GPIO51_nPIOW_MD);
++ set_GPIO_mode(GPIO52_nPCE_1_MD);
++ set_GPIO_mode(GPIO53_nPCE_2_MD);
++ set_GPIO_mode(GPIO54_pSKTSEL_MD); /* REVISIT: s/b dependent on num sockets */
++ set_GPIO_mode(GPIO55_nPREG_MD);
++ set_GPIO_mode(GPIO56_nPWAIT_MD);
++ set_GPIO_mode(GPIO57_nIOIS16_MD);
++
++
++ if(machine_is_lubbock()){
++#if defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_CSB226)
++ pcmcia_low_level=&lubbock_pcmcia_ops;
++#endif
++ } else if (machine_is_pxa_idp()) {
++ pcmcia_low_level=&pxa_idp_pcmcia_ops;
++ } else if( machine_is_pxa_cerf()){
++ pcmcia_low_level=&cerf_pcmcia_ops;
++ } else if (machine_is_trizeps2()){
++#ifdef CONFIG_ARCH_TRIZEPS2
++ pcmcia_low_level=&trizeps2_pcmcia_ops;
++#endif
++ }
++
++ if (!pcmcia_low_level) {
++ printk(KERN_ERR "This hardware is not supported by the PXA250/210 Card Service driver\n");
++ return -ENODEV;
++ }
++
++ pcmcia_init.handler=pxa_pcmcia_interrupt;
++
++ if((pxa_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){
++ printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n");
++ return -EIO;
++ }
++
++ state_array.size=pxa_pcmcia_socket_count;
++ state_array.state=state;
++
++ /* Configure MECR based on the number of sockets present. */
++ if (pxa_pcmcia_socket_count == 2) {
++ MECR |= GPIO_bit(0);
++ } else {
++ MECR &= ~GPIO_bit(0);
++ }
++
++ if(pcmcia_low_level->socket_state(&state_array)<0){
++ printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
++ return -EIO;
++ }
++
++ /* Well, it looks good to go. So we can now enable the PCMCIA
++ * controller.
++ */
++ MECR |= GPIO_bit(1);
++
++ /* We need to initialize the MCXX registers to default values
++ * here because we're not guaranteed to see a SetIOMap operation
++ * at runtime.
++ */
++
++ clock = get_lclk_frequency_10khz();
++
++ for(i=0; i<pxa_pcmcia_socket_count; ++i){
++ pxa_pcmcia_socket[i].k_state=state[i];
++
++ /* This is an interim fix. Apparently, SetSocket is no longer
++ * called to initialize each socket (prior to the first detect
++ * event). For now, we'll just manually set up the mask.
++ */
++ pxa_pcmcia_socket[i].cs_state.csc_mask=SS_DETECT;
++
++ pxa_pcmcia_socket[i].virt_io=(i==0)?PCMCIA_IO_0_BASE:PCMCIA_IO_1_BASE;
++ pxa_pcmcia_socket[i].phys_attr=_PCMCIAAttr(i);
++ pxa_pcmcia_socket[i].phys_mem=_PCMCIAMem(i);
++
++ /* REVISIT: cleanup these macros */
++ //MCIO_SET(i, PXA_PCMCIA_IO_ACCESS, clock);
++ //MCATTR_SET(i, PXA_PCMCIA_5V_MEM_ACCESS, clock);
++ //MCMEM_SET(i, PXA_PCMCIA_5V_MEM_ACCESS, clock);
++
++ pxa_pcmcia_socket[i].speed_io=PXA_PCMCIA_IO_ACCESS;
++ pxa_pcmcia_socket[i].speed_attr=PXA_PCMCIA_ATTR_MEM_ACCESS;
++ pxa_pcmcia_socket[i].speed_mem=PXA_PCMCIA_5V_MEM_ACCESS;
++ }
++
++/* REVISIT: cleanup these macros */
++MCMEM0 = ((pxa_mcxx_setup(PXA_PCMCIA_5V_MEM_ACCESS, clock)
++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++ | ((pxa_mcxx_asst(PXA_PCMCIA_5V_MEM_ACCESS, clock)
++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++ | ((pxa_mcxx_hold(PXA_PCMCIA_5V_MEM_ACCESS, clock)
++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++MCMEM1 = ((pxa_mcxx_setup(PXA_PCMCIA_5V_MEM_ACCESS, clock)
++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++ | ((pxa_mcxx_asst(PXA_PCMCIA_5V_MEM_ACCESS, clock)
++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++ | ((pxa_mcxx_hold(PXA_PCMCIA_5V_MEM_ACCESS, clock)
++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++MCATT0 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++ | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++ | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++MCATT1 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++ | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++ | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++MCIO0 = ((pxa_mcxx_setup(PXA_PCMCIA_IO_ACCESS, clock)
++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++ | ((pxa_mcxx_asst(PXA_PCMCIA_IO_ACCESS, clock)
++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++ | ((pxa_mcxx_hold(PXA_PCMCIA_IO_ACCESS, clock)
++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++MCIO1 = ((pxa_mcxx_setup(PXA_PCMCIA_IO_ACCESS, clock)
++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++ | ((pxa_mcxx_asst(PXA_PCMCIA_IO_ACCESS, clock)
++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++ | ((pxa_mcxx_hold(PXA_PCMCIA_IO_ACCESS, clock)
++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++
++#ifdef CONFIG_CPU_FREQ
++ if(cpufreq_register_notifier(&pxa_pcmcia_notifier_block) < 0){
++ printk(KERN_ERR "Unable to register CPU frequency change notifier\n");
++ return -ENXIO;
++ }
++#endif
++
++ /* Only advertise as many sockets as we can detect: */
++ if(register_ss_entry(pxa_pcmcia_socket_count,
++ &pxa_pcmcia_operations)<0){
++ printk(KERN_ERR "Unable to register socket service routine\n");
++ return -ENXIO;
++ }
++
++ /* Start the event poll timer. It will reschedule by itself afterwards. */
++ pxa_pcmcia_poll_event(0);
++
++ DEBUG(1, "pxa_cs: initialization complete\n");
++
++ return 0;
++
++} /* pxa_pcmcia_driver_init() */
++
++module_init(pxa_pcmcia_driver_init);
++
++
++/* pxa_pcmcia_driver_shutdown()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Invokes the low-level kernel service to free IRQs associated with this
++ * socket controller and reset GPIO edge detection.
++ */
++static void __exit pxa_pcmcia_driver_shutdown(void){
++
++ del_timer_sync(&poll_timer);
++ unregister_ss_entry(&pxa_pcmcia_operations);
++#ifdef CONFIG_CPU_FREQ
++ cpufreq_unregister_notifier(&pxa_pcmcia_notifier_block);
++#endif
++ pcmcia_low_level->shutdown();
++ flush_scheduled_tasks();
++
++ DEBUG(1, "pxa_cs: shutdown complete\n");
++}
++
++module_exit(pxa_pcmcia_driver_shutdown);
++
++
++/* pxa_pcmcia_init()
++ * ^^^^^^^^^^^^^^^^^^^^
++ * We perform all of the interesting initialization tasks in
++ * pxa_pcmcia_driver_init().
++ *
++ * Returns: 0
++ */
++static int pxa_pcmcia_init(unsigned int sock){
++
++ DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock);
++
++ return 0;
++}
++
++
++/* pxa_pcmcia_suspend()
++ * ^^^^^^^^^^^^^^^^^^^^^^^
++ * We don't currently perform any actions on a suspend.
++ *
++ * Returns: 0
++ */
++static int pxa_pcmcia_suspend(unsigned int sock)
++{
++ socket_state_t st;
++ int ret;
++
++ DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock);
++
++ st.Vcc = 0;
++ st.Vpp = 0;
++ st.flags = SS_RESET;
++
++ ret = pcmcia_low_level->configure_socket(sock, &st);
++
++ if (ret == 0)
++ pxa_pcmcia_socket[sock].cs_state = dead_socket;
++
++ return ret;
++}
++
++
++/* pxa_pcmcia_events()
++ * ^^^^^^^^^^^^^^^^^^^^^^
++ * Helper routine to generate a Card Services event mask based on
++ * state information obtained from the kernel low-level PCMCIA layer
++ * in a recent (and previous) sampling. Updates `prev_state'.
++ *
++ * Returns: an event mask for the given socket state.
++ */
++static inline unsigned pxa_pcmcia_events(struct pcmcia_state *state,
++ struct pcmcia_state *prev_state,
++ unsigned int mask,
++ unsigned int flags){
++ unsigned int events=0;
++
++ if(state->detect!=prev_state->detect){
++
++ DEBUG(2, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
++
++ events|=mask&SS_DETECT;
++ }
++
++ if(state->ready!=prev_state->ready){
++
++ DEBUG(2, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
++
++ events|=mask&((flags&SS_IOCARD)?0:SS_READY);
++ }
++
++ if(state->bvd1!=prev_state->bvd1){
++
++ DEBUG(2, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
++
++ events|=mask&(flags&SS_IOCARD)?SS_STSCHG:SS_BATDEAD;
++ }
++
++ if(state->bvd2!=prev_state->bvd2){
++
++ DEBUG(2, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
++
++ events|=mask&(flags&SS_IOCARD)?0:SS_BATWARN;
++ }
++
++ DEBUG(2, "events: %s%s%s%s%s%s\n",
++ (events==0)?"<NONE>":"",
++ (events&SS_DETECT)?"DETECT ":"",
++ (events&SS_READY)?"READY ":"",
++ (events&SS_BATDEAD)?"BATDEAD ":"",
++ (events&SS_BATWARN)?"BATWARN ":"",
++ (events&SS_STSCHG)?"STSCHG ":"");
++
++ *prev_state=*state;
++
++ return events;
++
++} /* pxa_pcmcia_events() */
++
++
++/* pxa_pcmcia_task_handler()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Processes serviceable socket events using the "eventd" thread context.
++ *
++ * Event processing (specifically, the invocation of the Card Services event
++ * callback) occurs in this thread rather than in the actual interrupt
++ * handler due to the use of scheduling operations in the PCMCIA core.
++ */
++static void pxa_pcmcia_task_handler(void *data) {
++ struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK];
++ struct pcmcia_state_array state_array;
++ int i, events, all_events, irq_status;
++
++ DEBUG(2, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
++
++ state_array.size=pxa_pcmcia_socket_count;
++ state_array.state=state;
++
++ do {
++
++ DEBUG(3, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__);
++
++ if((irq_status=pcmcia_low_level->socket_state(&state_array))<0)
++ printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n");
++
++ all_events=0;
++
++ if(irq_status>0){
++
++ for(i=0; i<state_array.size; ++i, all_events|=events)
++ if((events=
++ pxa_pcmcia_events(&state[i],
++ &pxa_pcmcia_socket[i].k_state,
++ pxa_pcmcia_socket[i].cs_state.csc_mask,
++ pxa_pcmcia_socket[i].cs_state.flags)))
++ if(pxa_pcmcia_socket[i].handler!=NULL)
++ pxa_pcmcia_socket[i].handler(pxa_pcmcia_socket[i].handler_info,
++ events);
++ }
++
++ } while(all_events);
++} /* pxa_pcmcia_task_handler() */
++
++static struct tq_struct pxa_pcmcia_task = {
++ routine: pxa_pcmcia_task_handler
++};
++
++
++/* pxa_pcmcia_poll_event()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Let's poll for events in addition to IRQs since IRQ only is unreliable...
++ */
++static void pxa_pcmcia_poll_event(unsigned long dummy)
++{
++ DEBUG(3, "%s(): polling for events\n", __FUNCTION__);
++ poll_timer.function = pxa_pcmcia_poll_event;
++ poll_timer.expires = jiffies + PXA_PCMCIA_POLL_PERIOD;
++ add_timer(&poll_timer);
++ schedule_task(&pxa_pcmcia_task);
++}
++
++
++/* pxa_pcmcia_interrupt()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Service routine for socket driver interrupts (requested by the
++ * low-level PCMCIA init() operation via pxa_pcmcia_thread()).
++ * The actual interrupt-servicing work is performed by
++ * pxa_pcmcia_thread(), largely because the Card Services event-
++ * handling code performs scheduling operations which cannot be
++ * executed from within an interrupt context.
++ */
++static void pxa_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs){
++ DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
++ schedule_task(&pxa_pcmcia_task);
++}
++
++
++/* pxa_pcmcia_register_callback()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the register_callback() operation for the in-kernel
++ * PCMCIA service (formerly SS_RegisterCallback in Card Services). If
++ * the function pointer `handler' is not NULL, remember the callback
++ * location in the state for `sock', and increment the usage counter
++ * for the driver module. (The callback is invoked from the interrupt
++ * service routine, pxa_pcmcia_interrupt(), to notify Card Services
++ * of interesting events.) Otherwise, clear the callback pointer in the
++ * socket state and decrement the module usage count.
++ *
++ * Returns: 0
++ */
++static int pxa_pcmcia_register_callback(unsigned int sock,
++ void (*handler)(void *,
++ unsigned int),
++ void *info){
++ if(handler==NULL){
++ pxa_pcmcia_socket[sock].handler=NULL;
++ MOD_DEC_USE_COUNT;
++ } else {
++ MOD_INC_USE_COUNT;
++ pxa_pcmcia_socket[sock].handler=handler;
++ pxa_pcmcia_socket[sock].handler_info=info;
++ }
++
++ return 0;
++}
++
++
++/* pxa_pcmcia_inquire_socket()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the inquire_socket() operation for the in-kernel PCMCIA
++ * service (formerly SS_InquireSocket in Card Services). Of note is
++ * the setting of the SS_CAP_PAGE_REGS bit in the `features' field of
++ * `cap' to "trick" Card Services into tolerating large "I/O memory"
++ * addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory
++ * resource database check. (Mapped memory is set up within the socket
++ * driver itself.)
++ *
++ * In conjunction with the STATIC_MAP capability is a new field,
++ * `io_offset', recommended by David Hinds. Rather than go through
++ * the SetIOMap interface (which is not quite suited for communicating
++ * window locations up from the socket driver), we just pass up
++ * an offset which is applied to client-requested base I/O addresses
++ * in alloc_io_space().
++ *
++ * Returns: 0 on success, -1 if no pin has been configured for `sock'
++ */
++static int pxa_pcmcia_inquire_socket(unsigned int sock,
++ socket_cap_t *cap){
++ struct pcmcia_irq_info irq_info;
++
++ DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
++
++ if(sock>=pxa_pcmcia_socket_count){
++ printk(KERN_ERR "pxa_cs: socket %u not configured\n", sock);
++ return -1;
++ }
++
++ /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
++ * force_low argument to validate_mem() in rsrc_mgr.c -- since in
++ * general, the mapped * addresses of the PCMCIA memory regions
++ * will not be within 0xffff, setting force_low would be
++ * undesirable.
++ *
++ * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
++ * resource database; we instead pass up physical address ranges
++ * and allow other parts of Card Services to deal with remapping.
++ *
++ * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
++ * not 32-bit CardBus devices.
++ */
++ cap->features=(SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD);
++
++ irq_info.sock=sock;
++ irq_info.irq=-1;
++
++ if(pcmcia_low_level->get_irq_info(&irq_info)<0){
++ printk(KERN_ERR "Error obtaining IRQ info from kernel for socket %u\n",
++ sock);
++ return -1;
++ }
++
++ cap->irq_mask=0;
++ cap->map_size=PAGE_SIZE;
++ cap->pci_irq=irq_info.irq;
++ cap->io_offset=pxa_pcmcia_socket[sock].virt_io;
++
++ return 0;
++
++} /* pxa_pcmcia_inquire_socket() */
++
++
++/* pxa_pcmcia_get_status()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the get_status() operation for the in-kernel PCMCIA
++ * service (formerly SS_GetStatus in Card Services). Essentially just
++ * fills in bits in `status' according to internal driver state or
++ * the value of the voltage detect chipselect register.
++ *
++ * As a debugging note, during card startup, the PCMCIA core issues
++ * three set_socket() commands in a row the first with RESET deasserted,
++ * the second with RESET asserted, and the last with RESET deasserted
++ * again. Following the third set_socket(), a get_status() command will
++ * be issued. The kernel is looking for the SS_READY flag (see
++ * setup_socket(), reset_socket(), and unreset_socket() in cs.c).
++ *
++ * Returns: 0
++ */
++static int pxa_pcmcia_get_status(unsigned int sock,
++ unsigned int *status){
++ struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK];
++ struct pcmcia_state_array state_array;
++
++ DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
++
++ state_array.size=pxa_pcmcia_socket_count;
++ state_array.state=state;
++
++ if((pcmcia_low_level->socket_state(&state_array))<0){
++ printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
++ return -1;
++ }
++
++ pxa_pcmcia_socket[sock].k_state=state[sock];
++
++ *status=state[sock].detect?SS_DETECT:0;
++
++ *status|=state[sock].ready?SS_READY:0;
++
++ /* The power status of individual sockets is not available
++ * explicitly from the hardware, so we just remember the state
++ * and regurgitate it upon request:
++ */
++ *status|=pxa_pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0;
++
++ if(pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)
++ *status|=state[sock].bvd1?SS_STSCHG:0;
++ else {
++ if(state[sock].bvd1==0)
++ *status|=SS_BATDEAD;
++ else if(state[sock].bvd2==0)
++ *status|=SS_BATWARN;
++ }
++
++ *status|=state[sock].vs_3v?SS_3VCARD:0;
++
++ *status|=state[sock].vs_Xv?SS_XVCARD:0;
++
++ DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n",
++ (*status&SS_DETECT)?"DETECT ":"",
++ (*status&SS_READY)?"READY ":"",
++ (*status&SS_BATDEAD)?"BATDEAD ":"",
++ (*status&SS_BATWARN)?"BATWARN ":"",
++ (*status&SS_POWERON)?"POWERON ":"",
++ (*status&SS_STSCHG)?"STSCHG ":"",
++ (*status&SS_3VCARD)?"3VCARD ":"",
++ (*status&SS_XVCARD)?"XVCARD ":"");
++
++ return 0;
++
++} /* pxa_pcmcia_get_status() */
++
++
++/* pxa_pcmcia_get_socket()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the get_socket() operation for the in-kernel PCMCIA
++ * service (formerly SS_GetSocket in Card Services). Not a very
++ * exciting routine.
++ *
++ * Returns: 0
++ */
++static int pxa_pcmcia_get_socket(unsigned int sock,
++ socket_state_t *state){
++
++ DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
++
++ /* This information was given to us in an earlier call to set_socket(),
++ * so we're just regurgitating it here:
++ */
++ *state=pxa_pcmcia_socket[sock].cs_state;
++
++ return 0;
++}
++
++
++/* pxa_pcmcia_set_socket()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the set_socket() operation for the in-kernel PCMCIA
++ * service (formerly SS_SetSocket in Card Services). We more or
++ * less punt all of this work and let the kernel handle the details
++ * of power configuration, reset, &c. We also record the value of
++ * `state' in order to regurgitate it to the PCMCIA core later.
++ *
++ * Returns: 0
++ */
++static int pxa_pcmcia_set_socket(unsigned int sock,
++ socket_state_t *state){
++
++ DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
++
++ DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n"
++ "\tVcc %d Vpp %d irq %d\n",
++ (state->csc_mask==0)?"<NONE>":"",
++ (state->csc_mask&SS_DETECT)?"DETECT ":"",
++ (state->csc_mask&SS_READY)?"READY ":"",
++ (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"",
++ (state->csc_mask&SS_BATWARN)?"BATWARN ":"",
++ (state->csc_mask&SS_STSCHG)?"STSCHG ":"",
++ (state->flags==0)?"<NONE>":"",
++ (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"",
++ (state->flags&SS_IOCARD)?"IOCARD ":"",
++ (state->flags&SS_RESET)?"RESET ":"",
++ (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
++ (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
++ state->Vcc, state->Vpp, state->io_irq);
++
++ if(pcmcia_low_level->configure_socket(sock, state)<0){
++ printk(KERN_ERR "Unable to configure socket %u\n", sock);
++ return -1;
++ }
++
++ pxa_pcmcia_socket[sock].cs_state=*state;
++
++ return 0;
++
++} /* pxa_pcmcia_set_socket() */
++
++
++/* pxa_pcmcia_get_io_map()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the get_io_map() operation for the in-kernel PCMCIA
++ * service (formerly SS_GetIOMap in Card Services). Just returns an
++ * I/O map descriptor which was assigned earlier by a set_io_map().
++ *
++ * Returns: 0 on success, -1 if the map index was out of range
++ */
++static int pxa_pcmcia_get_io_map(unsigned int sock,
++ struct pccard_io_map *map){
++
++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
++
++ if(map->map>=MAX_IO_WIN){
++ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
++ map->map);
++ return -1;
++ }
++
++ *map=pxa_pcmcia_socket[sock].io_map[map->map];
++
++ return 0;
++}
++
++
++/* pxa_pcmcia_set_io_map()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the set_io_map() operation for the in-kernel PCMCIA
++ * service (formerly SS_SetIOMap in Card Services). We configure
++ * the map speed as requested, but override the address ranges
++ * supplied by Card Services.
++ *
++ * Returns: 0 on success, -1 on error
++ */
++static int pxa_pcmcia_set_io_map(unsigned int sock,
++ struct pccard_io_map *map){
++ unsigned int clock, speed;
++ unsigned long mecr, start;
++
++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
++
++ DEBUG(4, "\tmap %u speed %u\n\tstart 0x%08lx stop 0x%08lx\n"
++ "\tflags: %s%s%s%s%s%s%s%s\n",
++ map->map, map->speed, map->start, map->stop,
++ (map->flags==0)?"<NONE>":"",
++ (map->flags&MAP_ACTIVE)?"ACTIVE ":"",
++ (map->flags&MAP_16BIT)?"16BIT ":"",
++ (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
++ (map->flags&MAP_0WS)?"0WS ":"",
++ (map->flags&MAP_WRPROT)?"WRPROT ":"",
++ (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"",
++ (map->flags&MAP_PREFETCH)?"PREFETCH ":"");
++
++ if(map->map>=MAX_IO_WIN){
++ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
++ map->map);
++ return -1;
++ }
++
++ if(map->flags&MAP_ACTIVE){
++
++ speed=(map->speed>0)?map->speed:PXA_PCMCIA_IO_ACCESS;
++
++ clock = get_lclk_frequency_10khz();
++
++ pxa_pcmcia_socket[sock].speed_io=speed;
++
++ if (sock == 0) {
++ MCIO0 = ((pxa_mcxx_setup(speed, clock)
++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++ | ((pxa_mcxx_asst(speed, clock)
++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++ | ((pxa_mcxx_hold(speed, clock)
++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++ } else {
++ MCIO1 = ((pxa_mcxx_setup(speed, clock)
++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++ | ((pxa_mcxx_asst(speed, clock)
++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++ | ((pxa_mcxx_hold(speed, clock)
++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++ }
++
++ DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n",
++ __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
++ MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock),
++ sock, MECR_BSIO_GET(mecr, sock));
++
++ }
++
++ start=map->start;
++
++ if(map->stop==1)
++ map->stop=PAGE_SIZE-1;
++
++ map->start=pxa_pcmcia_socket[sock].virt_io;
++ map->stop=map->start+(map->stop-start);
++
++ pxa_pcmcia_socket[sock].io_map[map->map]=*map;
++
++ return 0;
++
++} /* pxa_pcmcia_set_io_map() */
++
++
++/* pxa_pcmcia_get_mem_map()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the get_mem_map() operation for the in-kernel PCMCIA
++ * service (formerly SS_GetMemMap in Card Services). Just returns a
++ * memory map descriptor which was assigned earlier by a
++ * set_mem_map() request.
++ *
++ * Returns: 0 on success, -1 if the map index was out of range
++ */
++static int pxa_pcmcia_get_mem_map(unsigned int sock,
++ struct pccard_mem_map *map){
++
++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
++
++ if(map->map>=MAX_WIN){
++ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
++ map->map);
++ return -1;
++ }
++
++ *map=pxa_pcmcia_socket[sock].mem_map[map->map];
++
++ return 0;
++}
++
++
++/* pxa_pcmcia_set_mem_map()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the set_mem_map() operation for the in-kernel PCMCIA
++ * service (formerly SS_SetMemMap in Card Services). We configure
++ * the map speed as requested, but override the address ranges
++ * supplied by Card Services.
++ *
++ * Returns: 0 on success, -1 on error
++ */
++static int pxa_pcmcia_set_mem_map(unsigned int sock,
++ struct pccard_mem_map *map){
++ unsigned int clock, speed;
++ unsigned long mecr, start;
++
++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
++
++ DEBUG(4, "\tmap %u speed %u\n\tsys_start %#lx\n"
++ "\tsys_stop %#lx\n\tcard_start %#x\n"
++ "\tflags: %s%s%s%s%s%s%s%s\n",
++ map->map, map->speed, map->sys_start, map->sys_stop,
++ map->card_start, (map->flags==0)?"<NONE>":"",
++ (map->flags&MAP_ACTIVE)?"ACTIVE ":"",
++ (map->flags&MAP_16BIT)?"16BIT ":"",
++ (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
++ (map->flags&MAP_0WS)?"0WS ":"",
++ (map->flags&MAP_WRPROT)?"WRPROT ":"",
++ (map->flags&MAP_ATTRIB)?"ATTRIB ":"",
++ (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
++
++ if(map->map>=MAX_WIN){
++ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
++ map->map);
++ return -1;
++ }
++
++ if(map->flags&MAP_ACTIVE){
++ /* When clients issue RequestMap, the access speed is not always
++ * properly configured:
++ */
++ if(map->speed > 0)
++ speed = map->speed;
++ else
++ switch(pxa_pcmcia_socket[sock].cs_state.Vcc){
++ case 33:
++ speed = PXA_PCMCIA_3V_MEM_ACCESS;
++ break;
++ default:
++ speed = PXA_PCMCIA_5V_MEM_ACCESS;
++ }
++
++ clock = get_lclk_frequency_10khz();
++
++ if(map->flags&MAP_ATTRIB){
++ if (sock == 0) {
++ MCATT0 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++ | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++ | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++ } else {
++ MCATT1 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++ | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++ | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++ }
++ pxa_pcmcia_socket[sock].speed_attr=speed;
++ } else {
++ if (sock == 0) {
++ MCMEM0 = ((pxa_mcxx_setup(speed, clock)
++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++ | ((pxa_mcxx_asst(speed, clock)
++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++ | ((pxa_mcxx_hold(speed, clock)
++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++ } else {
++ MCMEM1 = ((pxa_mcxx_setup(speed, clock)
++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++ | ((pxa_mcxx_asst(speed, clock)
++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++ | ((pxa_mcxx_hold(speed, clock)
++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++ }
++ pxa_pcmcia_socket[sock].speed_mem=speed;
++ }
++ DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n",
++ __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
++ MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock),
++ sock, MECR_BSIO_GET(mecr, sock));
++ }
++
++ start=map->sys_start;
++
++ if(map->sys_stop==0)
++ map->sys_stop=PAGE_SIZE-1;
++
++ map->sys_start=(map->flags & MAP_ATTRIB)?\
++ pxa_pcmcia_socket[sock].phys_attr:\
++ pxa_pcmcia_socket[sock].phys_mem;
++
++ map->sys_stop=map->sys_start+(map->sys_stop-start);
++
++ pxa_pcmcia_socket[sock].mem_map[map->map]=*map;
++
++ return 0;
++
++} /* pxa_pcmcia_set_mem_map() */
++
++
++#if defined(CONFIG_PROC_FS)
++
++/* pxa_pcmcia_proc_setup()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the proc_setup() operation for the in-kernel PCMCIA
++ * service (formerly SS_ProcSetup in Card Services).
++ *
++ * Returns: 0 on success, -1 on error
++ */
++static void pxa_pcmcia_proc_setup(unsigned int sock,
++ struct proc_dir_entry *base){
++ struct proc_dir_entry *entry;
++
++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
++
++ if((entry=create_proc_entry("status", 0, base))==NULL){
++ printk(KERN_ERR "Unable to install \"status\" procfs entry\n");
++ return;
++ }
++
++ entry->read_proc=pxa_pcmcia_proc_status;
++ entry->data=(void *)sock;
++}
++
++
++/* pxa_pcmcia_proc_status()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the /proc/bus/pccard/??/status file.
++ *
++ * Returns: the number of characters added to the buffer
++ */
++static int pxa_pcmcia_proc_status(char *buf, char **start, off_t pos,
++ int count, int *eof, void *data){
++ char *p=buf;
++ unsigned int sock=(unsigned int)data;
++ unsigned int clock = get_lclk_frequency_10khz();
++ unsigned long mecr = MECR;
++
++ p+=sprintf(p, "k_flags : %s%s%s%s%s%s%s\n",
++ pxa_pcmcia_socket[sock].k_state.detect?"detect ":"",
++ pxa_pcmcia_socket[sock].k_state.ready?"ready ":"",
++ pxa_pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"",
++ pxa_pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"",
++ pxa_pcmcia_socket[sock].k_state.wrprot?"wrprot ":"",
++ pxa_pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"",
++ pxa_pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":"");
++
++ p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n",
++ pxa_pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"",
++ pxa_pcmcia_socket[sock].k_state.ready?"SS_READY ":"",
++ pxa_pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"",
++ pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
++ "SS_IOCARD ":"",
++ (pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD &&
++ pxa_pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"",
++ ((pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
++ (pxa_pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"",
++ ((pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
++ (pxa_pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"",
++ pxa_pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"",
++ pxa_pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":"");
++
++ p+=sprintf(p, "mask : %s%s%s%s%s\n",
++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\
++ "SS_DETECT ":"",
++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\
++ "SS_READY ":"",
++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\
++ "SS_BATDEAD ":"",
++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\
++ "SS_BATWARN ":"",
++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\
++ "SS_STSCHG ":"");
++
++ p+=sprintf(p, "cs_flags : %s%s%s%s%s\n",
++ pxa_pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\
++ "SS_PWR_AUTO ":"",
++ pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
++ "SS_IOCARD ":"",
++ pxa_pcmcia_socket[sock].cs_state.flags&SS_RESET?\
++ "SS_RESET ":"",
++ pxa_pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\
++ "SS_SPKR_ENA ":"",
++ pxa_pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\
++ "SS_OUTPUT_ENA ":"");
++
++ p+=sprintf(p, "Vcc : %d\n", pxa_pcmcia_socket[sock].cs_state.Vcc);
++
++ p+=sprintf(p, "Vpp : %d\n", pxa_pcmcia_socket[sock].cs_state.Vpp);
++
++ p+=sprintf(p, "irq : %d\n", pxa_pcmcia_socket[sock].cs_state.io_irq);
++
++ p+=sprintf(p, "I/O : %u (%u)\n", pxa_pcmcia_socket[sock].speed_io,
++ sock ?
++ pxa_pcmcia_cmd_time(clock,
++ ((MCIO1 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)) :
++ pxa_pcmcia_cmd_time(clock,
++ ((MCIO0 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)));
++
++ p+=sprintf(p, "attribute: %u (%u)\n", pxa_pcmcia_socket[sock].speed_attr,
++ sock ?
++ pxa_pcmcia_cmd_time(clock,
++ ((MCATT1 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)) :
++ pxa_pcmcia_cmd_time(clock,
++ ((MCATT0 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)));
++
++ p+=sprintf(p, "common : %u (%u)\n", pxa_pcmcia_socket[sock].speed_mem,
++ sock ?
++ pxa_pcmcia_cmd_time(clock,
++ ((MCMEM1 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)) :
++ pxa_pcmcia_cmd_time(clock,
++ ((MCMEM0 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)));
++
++ return p-buf;
++}
++
++#endif /* defined(CONFIG_PROC_FS) */
++
++
++#ifdef CONFIG_CPU_FREQ
++
++/* pxa_pcmcia_update_mecr()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * When pxa_pcmcia_notifier() decides that a MECR adjustment (due
++ * to a core clock frequency change) is needed, this routine establishes
++ * new BS_xx values consistent with the clock speed `clock'.
++ */
++static void pxa_pcmcia_update_mecr(unsigned int clock){
++ unsigned int sock;
++
++ for(sock = 0; sock < PXA_PCMCIA_MAX_SOCK; ++sock){
++
++ // REVISIT: MCXX macros needed here
++ // MECR_BSIO_SET(mecr, sock,
++// pxa_pcmcia_mecr_bs(pxa_pcmcia_socket[sock].speed_io,
++// clock));
++ // MECR_BSA_SET(mecr, sock,
++// pxa_pcmcia_mecr_bs(pxa_pcmcia_socket[sock].speed_attr,
++// clock));
++ // MECR_BSM_SET(mecr, sock,
++// pxa_pcmcia_mecr_bs(pxa_pcmcia_socket[sock].speed_mem,
++// clock));
++ }
++}
++
++/* pxa_pcmcia_notifier()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^
++ * When changing the processor core clock frequency, it is necessary
++ * to adjust the MECR timings accordingly. We've recorded the timings
++ * requested by Card Services, so this is just a matter of finding
++ * out what our current speed is, and then recomputing the new MECR
++ * values.
++ *
++ * Returns: 0 on success, -1 on error
++ */
++static int pxa_pcmcia_notifier(struct notifier_block *nb,
++ unsigned long val, void *data){
++ struct cpufreq_info *ci = data;
++
++ switch(val){
++ case CPUFREQ_MINMAX:
++
++ break;
++
++ case CPUFREQ_PRECHANGE:
++
++ if(ci->new_freq > ci->old_freq){
++ DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n",
++ __FUNCTION__,
++ ci->new_freq / 1000, (ci->new_freq / 100) % 10,
++ ci->old_freq / 1000, (ci->old_freq / 100) % 10);
++ pxa_pcmcia_update_mecr(ci->new_freq);
++ }
++
++ break;
++
++ case CPUFREQ_POSTCHANGE:
++
++ if(ci->new_freq < ci->old_freq){
++ DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n",
++ __FUNCTION__,
++ ci->new_freq / 1000, (ci->new_freq / 100) % 10,
++ ci->old_freq / 1000, (ci->old_freq / 100) % 10);
++ pxa_pcmcia_update_mecr(ci->new_freq);
++ }
++
++ break;
++
++ default:
++ printk(KERN_ERR "%s(): unknown CPU frequency event %lx\n", __FUNCTION__,
++ val);
++ return -1;
++
++ }
++
++ return 0;
++
++}
++
++static struct notifier_block pxa_pcmcia_notifier_block = {
++ notifier_call: pxa_pcmcia_notifier
++};
++
++#endif
++
+--- /dev/null
++++ linux-2.4.27/drivers/pcmcia/pxa/pxa.h
+@@ -0,0 +1,233 @@
++/*
++ * linux/drivers/pcmcia/pxa/pxa.h
++ *
++ * Author: George Davis
++ * Created: Jan 10, 2002
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Originally based upon linux/drivers/pcmcia/sa1100_generic.h
++ *
++ */
++
++/*======================================================================
++
++ Device driver for the PCMCIA control functionality of Intel
++ PXA250/210 microprocessors.
++
++ The contents of this file are subject to the Mozilla Public
++ License Version 1.1 (the "License"); you may not use this file
++ except in compliance with the License. You may obtain a copy of
++ the License at http://www.mozilla.org/MPL/
++
++ Software distributed under the License is distributed on an "AS
++ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ implied. See the License for the specific language governing
++ rights and limitations under the License.
++
++ The initial developer of the original code is John G. Dorsey
++ <john+@cs.cmu.edu>. Portions created by John G. Dorsey are
++ Copyright (C) 1999 John G. Dorsey. All Rights Reserved.
++
++ Alternatively, the contents of this file may be used under the
++ terms of the GNU Public License version 2 (the "GPL"), in which
++ case the provisions of the GPL are applicable instead of the
++ above. If you wish to allow the use of your version of this file
++ only under the terms of the GPL and not to allow others to use
++ your version of this file under the MPL, indicate your decision
++ by deleting the provisions above and replace them with the notice
++ and other provisions required by the GPL. If you do not delete
++ the provisions above, a recipient may use your version of this
++ file under either the MPL or the GPL.
++
++======================================================================*/
++
++#if !defined(_PCMCIA_PXA_H)
++# define _PCMCIA_PXA_H
++
++#include <pcmcia/cs_types.h>
++#include <pcmcia/ss.h>
++#include <pcmcia/bulkmem.h>
++#include <pcmcia/cistpl.h>
++#include "../cs_internal.h"
++
++#include <asm/arch/pcmcia.h>
++
++
++/* MECR: Expansion Memory Configuration Register
++ * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24)
++ *
++ * MECR layout is:
++ *
++ * FAST1 BSM1<4:0> BSA1<4:0> BSIO1<4:0> FAST0 BSM0<4:0> BSA0<4:0> BSIO0<4:0>
++ *
++ * (This layout is actually true only for the SA-1110; the FASTn bits are
++ * reserved on the SA-1100.)
++ */
++
++#define MCXX_SETUP_MASK (0x7f)
++#define MCXX_ASST_MASK (0x1f)
++#define MCXX_HOLD_MASK (0x3f)
++#define MCXX_SETUP_SHIFT (0)
++#define MCXX_ASST_SHIFT (7)
++#define MCXX_HOLD_SHIFT (14)
++
++
++#define MECR_SET(mecr, sock, shift, mask, bs) \
++((mecr)=((mecr)&~(((mask)<<(shift))<<\
++ ((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT)))|\
++ (((bs)<<(shift))<<((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT)))
++
++#define MECR_GET(mecr, sock, shift, mask) \
++((((mecr)>>(((sock)==0)?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT))>>\
++ (shift))&(mask))
++
++#define MECR_BSIO_SET(mecr, sock, bs) \
++MECR_SET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK, (bs))
++
++#define MECR_BSIO_GET(mecr, sock) \
++MECR_GET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK)
++
++#define MECR_BSA_SET(mecr, sock, bs) \
++MECR_SET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK, (bs))
++
++#define MECR_BSA_GET(mecr, sock) \
++MECR_GET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK)
++
++#define MECR_BSM_SET(mecr, sock, bs) \
++MECR_SET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK, (bs))
++
++#define MECR_BSM_GET(mecr, sock) \
++MECR_GET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK)
++
++#define MECR_FAST_SET(mecr, sock, fast) \
++MECR_SET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK, (fast))
++
++#define MECR_FAST_GET(mecr, sock) \
++MECR_GET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK)
++
++
++/* This function implements the BS value calculation for setting the MECR
++ * using integer arithmetic:
++ */
++static inline unsigned int pxa_pcmcia_mecr_bs(unsigned int pcmcia_cycle_ns,
++ unsigned int cpu_clock_khz){
++ unsigned int t = ((pcmcia_cycle_ns * cpu_clock_khz) / 6) - 1000000;
++ return (t / 1000000) + (((t % 1000000) == 0) ? 0 : 1);
++}
++
++static inline u_int pxa_mcxx_hold(u_int pcmcia_cycle_ns,
++ u_int mem_clk_10khz){
++ u_int code = pcmcia_cycle_ns * mem_clk_10khz;
++ return (code / 300000) + ((code % 300000) ? 1 : 0);
++}
++
++static inline u_int pxa_mcxx_asst(u_int pcmcia_cycle_ns,
++ u_int mem_clk_10khz){
++ u_int code = pcmcia_cycle_ns * mem_clk_10khz;
++ return (code / 300000) + ((code % 300000) ? 1 : 0);
++}
++
++static inline u_int pxa_mcxx_setup(u_int pcmcia_cycle_ns,
++ u_int mem_clk_10khz){
++ u_int code = pcmcia_cycle_ns * mem_clk_10khz;
++ return (code / 100000) + ((code % 100000) ? 1 : 0) + 1;
++}
++
++/* This function returns the (approxmiate) command assertion period, in
++ * nanoseconds, for a given CPU clock frequency and MCXX_ASST value:
++ */
++
++static inline u_int pxa_pcmcia_cmd_time(u_int mem_clk_10khz,
++ u_int pcmcia_mcxx_asst){
++ return (300000 * (pcmcia_mcxx_asst + 1) / mem_clk_10khz);
++}
++
++
++/* SA-1100 PCMCIA Memory and I/O timing
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * The SA-1110 Developer's Manual, section 10.2.5, says the following:
++ *
++ * "To calculate the recommended BS_xx value for each address space:
++ * divide the command width time (the greater of twIOWR and twIORD,
++ * or the greater of twWE and twOE) by processor cycle time; divide
++ * by 2; divide again by 3 (number of BCLK's per command assertion);
++ * round up to the next whole number; and subtract 1."
++ *
++ * The PC Card Standard, Release 7, section 4.13.4, says that twIORD
++ * has a minimum value of 165ns. Section 4.13.5 says that twIOWR has
++ * a minimum value of 165ns, as well. Section 4.7.2 (describing
++ * common and attribute memory write timing) says that twWE has a
++ * minimum value of 150ns for a 250ns cycle time (for 5V operation;
++ * see section 4.7.4), or 300ns for a 600ns cycle time (for 3.3V
++ * operation, also section 4.7.4). Section 4.7.3 says that taOE
++ * has a maximum value of 150ns for a 300ns cycle time (for 5V
++ * operation), or 300ns for a 600ns cycle time (for 3.3V operation).
++ *
++ * When configuring memory maps, Card Services appears to adopt the policy
++ * that a memory access time of "0" means "use the default." The default
++ * PCMCIA I/O command width time is 165ns. The default PCMCIA 5V attribute
++ * and memory command width time is 150ns; the PCMCIA 3.3V attribute and
++ * memory command width time is 300ns.
++ */
++
++/* The PXA 250 and PXA 210 Application Processors Developer's Manual
++ * was used to determine correct PXA_PCMCIA_IO_ACCES time
++ */
++
++#define PXA_PCMCIA_IO_ACCESS (165)
++
++/* Default PC Card Common Memory timings*/
++
++#define PXA_PCMCIA_5V_MEM_ACCESS (250)
++#define PXA_PCMCIA_3V_MEM_ACCESS (250)
++
++/* Atrribute Memory timing - must be constant via PC Card standart*/
++
++#define PXA_PCMCIA_ATTR_MEM_ACCESS (300)
++
++
++/* The socket driver actually works nicely in interrupt-driven form,
++ * so the (relatively infrequent) polling is "just to be sure."
++ */
++#define PXA_PCMCIA_POLL_PERIOD (2*HZ)
++
++
++/* This structure encapsulates per-socket state which we might need to
++ * use when responding to a Card Services query of some kind.
++ */
++struct pxa_pcmcia_socket {
++ socket_state_t cs_state;
++ struct pcmcia_state k_state;
++ unsigned int irq;
++ void (*handler)(void *, unsigned int);
++ void *handler_info;
++ pccard_io_map io_map[MAX_IO_WIN];
++ pccard_mem_map mem_map[MAX_WIN];
++ ioaddr_t virt_io, phys_attr, phys_mem;
++ unsigned short speed_io, speed_attr, speed_mem;
++};
++
++
++/* I/O pins replacing memory pins
++ * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75)
++ *
++ * These signals change meaning when going from memory-only to
++ * memory-or-I/O interface:
++ */
++#define iostschg bvd1
++#define iospkr bvd2
++
++
++/*
++ * Declaration for all implementation specific low_level operations.
++ */
++extern struct pcmcia_low_level lubbock_pcmcia_ops;
++extern struct pcmcia_low_level pxa_idp_pcmcia_ops;
++extern struct pcmcia_low_level cerf_pcmcia_ops;
++extern struct pcmcia_low_level trizeps2_pcmcia_ops;
++
++#endif /* !defined(_PCMCIA_PXA_H) */
+--- /dev/null
++++ linux-2.4.27/drivers/pcmcia/pxa/pxa_idp.c
+@@ -0,0 +1,297 @@
++/*
++ * linux/drivers/pcmcia/pxa/pxa_idp.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Copyright (c) 2002 Accelent Systems, Inc. All Rights Reserved
++ *
++ * Platform specific routines for the Accelent PXA250 IDP, based on those
++ * first done for the Lubbock.
++ *
++ * Version 1.0 2002-05-02 Jeff Sutherland <jeffs@accelent.com>
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++
++#include <pcmcia/ss.h>
++
++#include <asm/delay.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/arch/pcmcia.h>
++
++static int
++pxa_idp_pcmcia_init(struct pcmcia_init *init)
++{
++ int return_val = 0;
++
++ /* Set PCMCIA Socket 0 power to standby mode.
++ * PXA IDP has dedicated CPLD pins for all this stuff :-)
++ */
++
++ /* both slots disabled, reset NOT active */
++ IDP_CPLD_PCCARD_EN = PCC0_ENABLE | PCC1_ENABLE;
++
++ IDP_CPLD_PCCARD_PWR = 0; //all power to both slots off
++
++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S0_CD_VALID)) &=
++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S0_CD_VALID));
++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S1_CD_VALID)) &=
++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S1_CD_VALID));
++
++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S0_CD_VALID),
++ GPIO_BOTH_EDGES);
++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S1_CD_VALID),
++ GPIO_BOTH_EDGES);
++
++ /* irq's for slots: */
++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S0_RDYINT)) &=
++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S0_RDYINT));
++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S1_RDYINT)) &=
++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S1_RDYINT));
++
++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S0_RDYINT),
++ GPIO_FALLING_EDGE);
++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S1_RDYINT),
++ GPIO_FALLING_EDGE);
++
++ return_val =
++ request_irq(PCMCIA_S0_CD_VALID, init->handler, SA_INTERRUPT,
++ "PXA PCMCIA CD0", NULL);
++
++ if (return_val < 0)
++ return -1;
++
++ return_val +=
++ request_irq(PCMCIA_S1_CD_VALID, init->handler, SA_INTERRUPT,
++ "PXA PCMCIA CD1", NULL);
++
++ if (return_val < 0) {
++ free_irq(PCMCIA_S0_CD_VALID, NULL);
++ return -1;
++ }
++
++ return 2;
++}
++
++static int
++pxa_idp_pcmcia_shutdown(void)
++{
++
++ free_irq(PCMCIA_S0_CD_VALID, NULL);
++ free_irq(PCMCIA_S1_CD_VALID, NULL);
++
++ IDP_CPLD_PCCARD_EN = 0x03; //disable slots
++ udelay(200);
++ IDP_CPLD_PCCARD_PWR = 0; //shut off all power
++
++ return 0;
++}
++
++static int
++pxa_idp_pcmcia_socket_state(struct pcmcia_state_array *state_array)
++{
++ unsigned long status;
++ int return_val = 1;
++ int i;
++ volatile unsigned long *stat_regs[2] = { &IDP_CPLD_PCCARD0_STATUS,
++ &IDP_CPLD_PCCARD1_STATUS
++ };
++
++ if (state_array->size < 2)
++ return -1;
++
++ memset(state_array->state, 0,
++ (state_array->size) * sizeof (struct pcmcia_state));
++
++ for (i = 0; i < 2; i++) {
++
++ status = *stat_regs[i];
++
++ /* this one is a gpio */
++ state_array->state[i].detect = (PCC_DETECT(i)) ? 0 : 1;
++
++ state_array->state[i].ready =
++ ((status & _PCC_IRQ) == 0) ? 0 : 1;
++ state_array->state[i].bvd1 = (status & PCC_BVD1) ? 0 : 1;
++ state_array->state[i].bvd2 = (status & PCC_BVD2) ? 0 : 1;
++ state_array->state[i].wrprot =
++ (status & _PCC_WRPROT) ? 1 : 0;
++ state_array->state[i].vs_3v = (status & PCC_VS1) ? 0 : 1;
++ state_array->state[i].vs_Xv = (status & PCC_VS2) ? 0 : 1;
++ }
++
++ return return_val;
++}
++
++static int
++pxa_idp_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
++{
++ switch (info->sock) {
++ case 0:
++ info->irq = PCMCIA_S0_RDYINT;
++ break;
++
++ case 1:
++ info->irq = PCMCIA_S1_RDYINT;
++ break;
++
++ default:
++ return -1;
++ }
++
++ return 0;
++}
++
++static int
++pxa_idp_pcmcia_configure_socket(unsigned int sock, socket_state_t *state)
++{
++ /* The PXA Idp uses the Maxim MAX1602, with the following connections:
++ *
++ * Socket 0 (PCMCIA):
++ * MAX1602 PXA_IDP Register
++ * Pin Signal IDP_CPLD_PCCARD_PWR:
++ * ----- ------- ----------------------
++ * A0VPP PCC0_PWR0 bit0
++ * A1VPP PCC0_PWR1 bit1
++ * A0VCC PCC0_PWR2 bit2
++ * A1VCC PCC0_PWR3 bit3
++ * VX VCC
++ * VY +3.3V
++ * 12IN +12V
++ * CODE +3.3V Cirrus Code, CODE = High (VY)
++ *
++ * Socket 1 (PCMCIA):
++ * MAX1602 PXA_IDP Register
++ * Pin Signal IDP_CPLD_PCCARD_PWR:
++ * ----- ------- ----------------------
++ * A0VPP PCC1_PWR0 bit4
++ * A1VPP PCC1_PWR1 bit5
++ * A0VCC PCC1_PWR2 bit6
++ * A1VCC PCC1_PWR3 bit7
++ * VX VCC
++ * VY +3.3V
++ * 12IN +12V
++ * CODE +3.3V Cirrus Code, CODE = High (VY)
++ *
++ */
++
++ switch (sock) {
++ case 0:
++ switch (state->Vcc) {
++ case 0:
++ IDP_CPLD_PCCARD_EN |= PCC0_ENABLE; // disable socket
++ udelay(200);
++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR2 | PCC0_PWR3);
++ break;
++
++ case 33:
++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR2 | PCC0_PWR3);
++ IDP_CPLD_PCCARD_PWR |= PCC0_PWR3;
++ IDP_CPLD_PCCARD_EN &= ~PCC0_ENABLE; //turn it on
++ break;
++
++ case 50:
++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR2 | PCC0_PWR3);
++ IDP_CPLD_PCCARD_PWR |= PCC0_PWR2;
++ IDP_CPLD_PCCARD_EN &= ~PCC0_ENABLE;
++ break;
++
++ default:
++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
++ __FUNCTION__, state->Vcc);
++ return -1;
++ }
++
++ switch (state->Vpp) {
++ case 0:
++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR0 | PCC0_PWR1);
++ break;
++
++ case 120:
++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR0 | PCC0_PWR1);
++ IDP_CPLD_PCCARD_PWR |= PCC0_PWR1;
++ break;
++
++ default:
++ if (state->Vpp == state->Vcc)
++ IDP_CPLD_PCCARD_PWR =
++ (IDP_CPLD_PCCARD_PWR &
++ ~(PCC0_PWR0 | PCC0_PWR1)) | PCC0_PWR0;
++ else {
++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
++ __FUNCTION__, state->Vpp);
++ return -1;
++ }
++ }
++
++ IDP_CPLD_PCCARD_EN =
++ (state->flags & SS_RESET) ? (IDP_CPLD_PCCARD_EN | PCC0_RESET)
++ : (IDP_CPLD_PCCARD_EN & ~PCC0_RESET);
++ break;
++
++ case 1:
++ switch (state->Vcc) {
++ case 0:
++ IDP_CPLD_PCCARD_EN |= PCC1_ENABLE; // disable socket
++ udelay(200);
++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3);
++ break;
++
++ case 33:
++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3);
++ IDP_CPLD_PCCARD_PWR |= PCC1_PWR3;
++ IDP_CPLD_PCCARD_EN &= ~PCC1_ENABLE; //turn it on
++ break;
++
++ case 50:
++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3);
++ IDP_CPLD_PCCARD_PWR |= PCC1_PWR2;
++ IDP_CPLD_PCCARD_EN &= ~PCC1_ENABLE;
++ break;
++
++ default:
++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
++ __FUNCTION__, state->Vcc);
++ return -1;
++ }
++
++ switch (state->Vpp) {
++ case 0:
++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1);
++ break;
++
++ case 120:
++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1);
++ IDP_CPLD_PCCARD_PWR |= PCC1_PWR1;
++ break;
++
++ default:
++ if (state->Vpp == state->Vcc)
++ IDP_CPLD_PCCARD_PWR =
++ (IDP_CPLD_PCCARD_PWR &
++ ~(PCC1_PWR0 | PCC1_PWR1)) | PCC1_PWR0;
++ else {
++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
++ __FUNCTION__, state->Vpp);
++ return -1;
++ }
++ }
++ IDP_CPLD_PCCARD_EN = (state->flags & SS_RESET) ? (IDP_CPLD_PCCARD_EN | PCC1_RESET)
++ : (IDP_CPLD_PCCARD_EN & ~PCC1_RESET);
++ break;
++ }
++ return 0;
++}
++
++struct pcmcia_low_level pxa_idp_pcmcia_ops = {
++ pxa_idp_pcmcia_init,
++ pxa_idp_pcmcia_shutdown,
++ pxa_idp_pcmcia_socket_state,
++ pxa_idp_pcmcia_get_irq_info,
++ pxa_idp_pcmcia_configure_socket
++};
+--- /dev/null
++++ linux-2.4.27/drivers/pcmcia/pxa/trizeps2.c
+@@ -0,0 +1,187 @@
++/*
++ * linux/drivers/pcmcia/pxa/trizeps2.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Copyright (c) 2002 Accelent Systems, Inc. All Rights Reserved
++ *
++ * Platform specific routines for the Keith-n-Koep Trizeps-II, based on IDP
++ *
++ * Copyright (c) 2003 Teradyne DS, Ltd.
++ * Port to Trizeps-2 MT6N board by Luc De Cock
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++
++#include <pcmcia/ss.h>
++
++#include <asm/delay.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/arch/pcmcia.h>
++
++static int trizeps2_pcmcia_init(struct pcmcia_init *init)
++{
++ int return_val = 0;
++ unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE;
++ unsigned short val;
++
++ /* reset the PCMCIA controller */
++ val = trizeps2_bcr_shadow | BCR_PCMCIA_RESET;
++ *bcr = val;
++ udelay(500);
++ /* un-reset it again */
++ trizeps2_bcr_shadow &= ~BCR_PCMCIA_RESET;
++ /* enable the PCMCIA buffer */
++ trizeps2_bcr_shadow &= ~(1 << 5);
++ *bcr = trizeps2_bcr_shadow;
++
++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S_CD_VALID)) &=
++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S_CD_VALID));
++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S_CD_VALID),
++ PCMCIA_S_CD_VALID_EDGE);
++ GPDR(IRQ_TO_GPIO(PCMCIA_S_RDYINT)) &=
++ ~GPIO_bit(IRQ_TO_GPIO(PCMCIA_S_RDYINT));
++ set_GPIO_IRQ_edge(IRQ_TO_GPIO(PCMCIA_S_RDYINT),
++ PCMCIA_S_RDYINT_EDGE);
++
++ return_val = request_irq(PCMCIA_S_CD_VALID, init->handler, SA_INTERRUPT,
++ "PXA PCMCIA CD", NULL);
++ if (return_val < 0) {
++ return -1;
++ }
++ /* only 1 slot */
++ return 1;
++}
++
++static int trizeps2_pcmcia_shutdown(void)
++{
++ free_irq(PCMCIA_S_CD_VALID, NULL);
++
++ unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE;
++ trizeps2_bcr_shadow |= (1 << 5); /* pcmcia buffer off */
++ *bcr = trizeps2_bcr_shadow;
++ trizeps2_bcr_shadow &= 0xFFF0; /* pcmcia control logic grounded */
++ *bcr = trizeps2_bcr_shadow;
++
++ return 0;
++}
++
++static int trizeps2_pcmcia_socket_state(struct pcmcia_state_array *state_array)
++{
++ unsigned long status;
++ int return_val = 1;
++ volatile unsigned short *stat_regs[1] = {
++ &TRIZEPS2_PCCARD_STATUS
++ };
++
++ if (state_array->size < 1)
++ return -1;
++
++ memset(state_array->state, 0,
++ (state_array->size) * sizeof (struct pcmcia_state));
++
++ status = *stat_regs[0];
++
++ /* this one is a gpio */
++ state_array->state[0].detect = (PCC_DETECT) ? 0 : 1;
++ state_array->state[0].ready = (PCC_READY) ? 1 : 0;
++ state_array->state[0].bvd1 = (status & PCC_BVD1) ? 1 : 0;
++ state_array->state[0].bvd2 = (status & PCC_BVD2) ? 1 : 0;
++ state_array->state[0].wrprot = 0; /* r/w all the time */
++ state_array->state[0].vs_3v = (status & PCC_VS1) ? 0 : 1;
++ state_array->state[0].vs_Xv = (status & PCC_VS2) ? 0 : 1;
++
++ return return_val;
++}
++
++static int trizeps2_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
++{
++ switch (info->sock) {
++ case 0:
++ info->irq = PCMCIA_S_RDYINT;
++ break;
++
++ default:
++ return -1;
++ }
++
++ return 0;
++}
++
++static int trizeps2_pcmcia_configure_socket(unsigned int sock, socket_state_t *state)
++{
++ unsigned short cntr_logic = trizeps2_bcr_shadow & 0xF;
++ unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE;
++
++ /* configure Vcc and Vpp */
++ switch (sock) {
++ case 0:
++ switch (state->Vcc) {
++ case 0:
++ cntr_logic &= ~(PCC_3V | PCC_5V);
++ break;
++
++ case 33:
++ cntr_logic &= ~(PCC_3V | PCC_5V);
++ cntr_logic |= PCC_3V;
++ break;
++
++ case 50:
++ cntr_logic &= ~(PCC_3V | PCC_5V);
++ cntr_logic |= PCC_5V;
++ break;
++
++ default:
++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
++ __FUNCTION__, state->Vcc);
++ return -1;
++ }
++
++ switch (state->Vpp) {
++ case 0:
++ cntr_logic &= ~(PCC_EN0 | PCC_EN1);
++ break;
++
++ case 120:
++ cntr_logic &= ~(PCC_EN0 | PCC_EN1);
++ cntr_logic |= PCC_EN1;
++ break;
++
++ default:
++ if (state->Vpp == state->Vcc) {
++ cntr_logic &= ~(PCC_EN0 | PCC_EN1);
++ cntr_logic |= PCC_EN0;
++ }
++ else {
++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
++ __FUNCTION__, state->Vpp);
++ return -1;
++ }
++ }
++ trizeps2_bcr_shadow &= ~(PCC_EN0 | PCC_EN1 | PCC_3V | PCC_5V |
++ BCR_PCMCIA_RESET);
++ trizeps2_bcr_shadow |= cntr_logic;
++ *bcr = trizeps2_bcr_shadow;
++ /* reset PCMCIA controller if requested */
++ trizeps2_bcr_shadow |=
++ (state->flags & SS_RESET) ? BCR_PCMCIA_RESET : 0;
++ *bcr = trizeps2_bcr_shadow;
++ udelay(500);
++ break;
++ }
++ return 0;
++}
++
++struct pcmcia_low_level trizeps2_pcmcia_ops = {
++ trizeps2_pcmcia_init,
++ trizeps2_pcmcia_shutdown,
++ trizeps2_pcmcia_socket_state,
++ trizeps2_pcmcia_get_irq_info,
++ trizeps2_pcmcia_configure_socket
++};
++
+--- linux-2.4.27/drivers/pcmcia/sa1100_cerf.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/pcmcia/sa1100_cerf.c
+@@ -7,15 +7,25 @@
+ */
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
++#include <linux/delay.h>
+
+ #include <asm/hardware.h>
+ #include <asm/irq.h>
+-#include "sa1100_generic.h"
+
+-#ifdef CONFIG_SA1100_CERF_CPLD
+-#define CERF_SOCKET 0
++#include <pcmcia/ss.h>
++#include <asm/arch/pcmcia.h>
++#include "sa1100_cerf.h"
++
++/*
++ * Set this to zero to remove all the debug statements via
++ * dead code elimination
++ */
++//#define DEBUGGING 1
++
++#if DEBUGGING
++static unsigned int pcmcia_debug = DEBUGGING;
+ #else
+-#define CERF_SOCKET 1
++#define pcmcia_debug 0 /* gcc will remove all the debug code for us */
+ #endif
+
+ static struct irqs {
+@@ -23,122 +33,178 @@
+ unsigned int gpio;
+ const char *str;
+ } irqs[] = {
+- { IRQ_GPIO_CF_CD, GPIO_CF_CD, "CF_CD" },
+- { IRQ_GPIO_CF_BVD2, GPIO_CF_BVD2, "CF_BVD2" },
+- { IRQ_GPIO_CF_BVD1, GPIO_CF_BVD1, "CF_BVD1" }
++ { PCMCIA_IRQ_CF_CD, PCMCIA_GPIO_CF_CD_EDGE, "CF_CD" },
++ { PCMCIA_IRQ_CF_BVD2, PCMCIA_GPIO_CF_BVD2_EDGE, "CF_BVD2" },
++ { PCMCIA_IRQ_CF_BVD1, PCMCIA_GPIO_CF_BVD1_EDGE, "CF_BVD1" }
+ };
+
++static void cerf_pcmcia_reset( void)
++{
++ int i;
++
++ // Make sure SKTSEL is 0 (single slot)
++ set_GPIO_mode(54 | GPIO_OUT);
++ GPCR1 = GPIO_bit(54);
++ set_GPIO_mode(GPIO54_pSKTSEL_MD);
++
++ PCMCIA_GPCR = PCMCIA_GPIO_CF_RESET_MASK;
++ mdelay(300);
++
++ PCMCIA_GPSR = PCMCIA_GPIO_CF_RESET_MASK;
++ udelay(20);
++
++ PCMCIA_GPCR = PCMCIA_GPIO_CF_RESET_MASK;
++ mdelay(50);
++
++ for( i=0; i<10; i++)
++ {
++ if( cerf_pcmcia_level_ready()) break;
++ mdelay(100);
++ }
++}
++
+ static int cerf_pcmcia_init(struct pcmcia_init *init)
+ {
+- int i, res;
++ int i, res;
+
+- set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
++ if( pcmcia_debug)
++ printk( KERN_INFO "cerf_pcmcia_init: enter\n");
+
+- for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+- set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES);
+- res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+- irqs[i].str, NULL);
+- if (res)
+- goto irq_err;
+- }
++ cerf_pcmcia_set_gpio_direction();
+
+- return 2;
++ set_GPIO_IRQ_edge( PCMCIA_GPIO_CF_IRQ_EDGE, GPIO_FALLING_EDGE );
+
+- irq_err:
+- printk(KERN_ERR "%s: Request for IRQ%d failed\n", __FUNCTION__, irqs[i].irq);
++ for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+
+- while (i--)
+- free_irq(irqs[i].irq, NULL);
++ set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES);
+
+- return -1;
++ res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
++ irqs[i].str, NULL);
++ if (res)
++ goto irq_err;
++ }
++
++ printk( KERN_INFO "PCMCIA for Cerf: OK\n");
++
++ return CERF_SOCKET+1; /* last socket used +1 */
++
++irq_err:
++ printk(KERN_ERR "%s: Request for IRQ%d failed\n",
++ __FUNCTION__, irqs[i].irq);
++
++ while (i--)
++ free_irq(irqs[i].irq, NULL);
++
++ return -1;
+ }
+
+ static int cerf_pcmcia_shutdown(void)
+ {
+- int i;
++ int i;
++ if( pcmcia_debug)
++ printk( KERN_INFO "cerf_pcmcia_shutdown: enter\n");
+
+- for (i = 0; i < ARRAY_SIZE(irqs); i++)
+- free_irq(irqs[i].irq, NULL);
++ for (i = 0; i < ARRAY_SIZE(irqs); i++)
++ free_irq(irqs[i].irq, NULL);
+
+- return 0;
++ return 0;
+ }
+
+-static int cerf_pcmcia_socket_state(struct pcmcia_state_array
+- *state_array){
+- unsigned long levels;
+- int i = CERF_SOCKET;
++static int cerf_pcmcia_socket_state(struct pcmcia_state_array *state_array)
++{
++ int i = CERF_SOCKET;
+
+- if(state_array->size<2) return -1;
++ if( pcmcia_debug > 3)
++ printk( KERN_INFO "cerf_pcmcia_socket_state: i=%d, size=%d\n",
++ i, state_array->size);
+
+- levels=GPLR;
++ memset(state_array->state, 0,
++ (state_array->size)*sizeof(struct pcmcia_state));
+
+- state_array->state[i].detect=((levels & GPIO_CF_CD)==0)?1:0;
+- state_array->state[i].ready=(levels & GPIO_CF_IRQ)?1:0;
+- state_array->state[i].bvd1=(levels & GPIO_CF_BVD1)?1:0;
+- state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0;
+- state_array->state[i].wrprot=0;
+- state_array->state[i].vs_3v=1;
+- state_array->state[i].vs_Xv=0;
++ state_array->state[i].detect = cerf_pcmcia_level_detect();
++ state_array->state[i].ready = cerf_pcmcia_level_ready();
++ state_array->state[i].bvd1 = cerf_pcmcia_level_bvd1();
++ state_array->state[i].bvd2 = cerf_pcmcia_level_bvd2();
++ state_array->state[i].wrprot=0;
++ state_array->state[i].vs_3v=1;
++ state_array->state[i].vs_Xv=0;
+
+- return 1;
++ if( pcmcia_debug > 3)
++ printk( KERN_INFO "cerf_pcmcia_socket_state: "
++ "detect=%d ready=%d bvd1=%d bvd2=%d\n",
++ state_array->state[i].detect,
++ state_array->state[i].ready,
++ state_array->state[i].bvd1,
++ state_array->state[i].bvd2);
++
++ return 1;
+ }
+
+ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+
+- if(info->sock>1) return -1;
++ if( pcmcia_debug)
++ printk( KERN_INFO "cerf_pcmcia_get_irq_info: "
++ "sock=%d\n", info->sock);
+
+- if (info->sock == CERF_SOCKET)
+- info->irq=IRQ_GPIO_CF_IRQ;
++ if(info->sock>1) return -1;
+
+- return 0;
++ if (info->sock == CERF_SOCKET)
++ info->irq=PCMCIA_IRQ_CF_IRQ;
++
++ if( pcmcia_debug)
++ printk( KERN_INFO "cerf_pcmcia_get_irq_info: irq=%d\n",info->irq);
++
++ return 0;
+ }
+
+-static int cerf_pcmcia_configure_socket(const struct pcmcia_configure
+- *configure)
++static int cerf_pcmcia_configure_socket( unsigned int sock, socket_state_t *state)
+ {
+- if(configure->sock>1)
+- return -1;
++ if( pcmcia_debug)
++ printk( KERN_INFO "cerf_pcmcia_configure_socket:"
++ "sock=%d vcc=%d flags=%x\n",
++ sock, state->Vcc, state->flags);
+
+- if (configure->sock != CERF_SOCKET)
+- return 0;
++ if(sock>1)
++ return -1;
+
+- switch(configure->vcc){
+- case 0:
+- break;
++ if (sock != CERF_SOCKET)
++ return 0;
+
+- case 50:
+- case 33:
+-#ifdef CONFIG_SA1100_CERF_CPLD
+- GPCR = GPIO_PWR_SHUTDOWN;
++ switch(state->Vcc){
++ case 0:
++ break;
++
++ case 50:
++ case 33:
++#if defined(CONFIG_SA1100_CERF_CPLD)
++ PCMCIA_GPDR |= PCMCIA_PWR_SHUTDOWN;
++ PCMCIA_GPCR |= PCMCIA_PWR_SHUTDOWN;
+ #endif
+- break;
++ /* voltage selected automatically */
++ break;
+
+- default:
+- printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+- configure->vcc);
+- return -1;
+- }
++ default:
++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
++ __FUNCTION__, state->Vcc);
++ return -1;
++ }
+
+- if(configure->reset)
+- {
+-#ifdef CONFIG_SA1100_CERF_CPLD
+- GPSR = GPIO_CF_RESET;
+-#endif
+- }
+- else
+- {
+-#ifdef CONFIG_SA1100_CERF_CPLD
+- GPCR = GPIO_CF_RESET;
+-#endif
+- }
++ if(state->flags&SS_RESET)
++ {
++ cerf_pcmcia_reset();
++ }
+
+- return 0;
++ return 0;
+ }
+
++#ifdef CONFIG_SA1100_CERF
+ static int cerf_pcmcia_socket_init(int sock)
+ {
+ int i;
+
++ if( pcmcia_debug)
++ printk( KERN_INFO "cerf_pcmcia_socket_init: sock=%d\n",sock);
++
+ if (sock == CERF_SOCKET)
+ for (i = 0; i < ARRAY_SIZE(irqs); i++)
+ set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES);
+@@ -150,21 +216,26 @@
+ {
+ int i;
+
++ if( pcmcia_debug)
++ printk( KERN_INFO "cerf_pcmcia_socket_suspend: sock=%d\n",sock);
++
+ if (sock == CERF_SOCKET)
+ for (i = 0; i < ARRAY_SIZE(irqs); i++)
+ set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES);
+
+ return 0;
+ }
++#endif
+
+ struct pcmcia_low_level cerf_pcmcia_ops = {
+- init: cerf_pcmcia_init,
+- shutdown: cerf_pcmcia_shutdown,
+- socket_state: cerf_pcmcia_socket_state,
+- get_irq_info: cerf_pcmcia_get_irq_info,
+- configure_socket: cerf_pcmcia_configure_socket,
++init: cerf_pcmcia_init,
++shutdown: cerf_pcmcia_shutdown,
++socket_state: cerf_pcmcia_socket_state,
++get_irq_info: cerf_pcmcia_get_irq_info,
++configure_socket: cerf_pcmcia_configure_socket,
+
+- socket_init: cerf_pcmcia_socket_init,
+- socket_suspend: cerf_pcmcia_socket_suspend,
++#ifdef CONFIG_SA1100_CERF
++socket_init: cerf_pcmcia_socket_init,
++socket_suspend: cerf_pcmcia_socket_suspend,
++#endif
+ };
+-
+--- /dev/null
++++ linux-2.4.27/drivers/pcmcia/sa1100_cerf.h
+@@ -0,0 +1,138 @@
++/*
++ * drivers/pcmcia/cerf.h
++ *
++ * PCMCIA implementation routines for CerfBoard
++ * Based off the Assabet.
++ *
++ */
++#ifndef _LINUX_PCMCIA_CERF_H
++#define _LINUX_PCMCIA_CERF_H
++
++#include <linux/config.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/arch/pcmcia.h>
++
++#ifdef CONFIG_PXA_CERF /* PXA */
++
++#define PCMCIA_GPCR GPCR0
++#define PCMCIA_GPSR GPSR0
++
++#define PCMCIA_GPIO_CF_CD 14
++#define PCMCIA_GPIO_CF_IRQ 13
++#define PCMCIA_GPIO_CF_RESET 12
++#ifdef CONFIG_PXA_CERF_PDA
++# define PCMCIA_GPIO_CF_BVD1 11
++# define PCMCIA_GPIO_CF_BVD2 10
++#elif defined( CONFIG_PXA_CERF_BOARD)
++# define PCMCIA_GPIO_CF_BVD1 32
++# define PCMCIA_GPIO_CF_BVD2 10
++#endif
++
++#define PCMCIA_GPIO_CF_CD_MASK (GPIO_bit(PCMCIA_GPIO_CF_CD))
++#define PCMCIA_GPIO_CF_IRQ_MASK (GPIO_bit(PCMCIA_GPIO_CF_IRQ))
++#define PCMCIA_GPIO_CF_RESET_MASK (GPIO_bit(PCMCIA_GPIO_CF_RESET))
++#define PCMCIA_GPIO_CF_BVD1_MASK (GPIO_bit(PCMCIA_GPIO_CF_BVD1))
++#define PCMCIA_GPIO_CF_BVD2_MASK (GPIO_bit(PCMCIA_GPIO_CF_BVD2))
++
++#define PCMCIA_GPIO_CF_CD_EDGE PCMCIA_GPIO_CF_CD
++#define PCMCIA_GPIO_CF_IRQ_EDGE PCMCIA_GPIO_CF_IRQ
++#define PCMCIA_GPIO_CF_RESET_EDGE PCMCIA_GPIO_CF_RESET
++#define PCMCIA_GPIO_CF_BVD1_EDGE PCMCIA_GPIO_CF_BVD1
++#define PCMCIA_GPIO_CF_BVD2_EDGE PCMCIA_GPIO_CF_BVD2
++
++#define PCMCIA_IRQ_CF_CD IRQ_GPIO(PCMCIA_GPIO_CF_CD)
++#define PCMCIA_IRQ_CF_IRQ IRQ_GPIO(PCMCIA_GPIO_CF_IRQ)
++#define PCMCIA_IRQ_CF_BVD1 IRQ_GPIO(PCMCIA_GPIO_CF_BVD1)
++#define PCMCIA_IRQ_CF_BVD2 IRQ_GPIO(PCMCIA_GPIO_CF_BVD2)
++
++#define PCMCIA_PWR_SHUTDOWN 0 /* not needed */
++#define CERF_SOCKET 0
++
++inline void cerf_pcmcia_set_gpio_direction(void)
++{
++ GPDR(PCMCIA_GPIO_CF_CD) &= ~(PCMCIA_GPIO_CF_CD_MASK);
++ GPDR(PCMCIA_GPIO_CF_BVD1) &= ~(PCMCIA_GPIO_CF_BVD1_MASK);
++ GPDR(PCMCIA_GPIO_CF_BVD2) &= ~(PCMCIA_GPIO_CF_BVD2_MASK);
++ GPDR(PCMCIA_GPIO_CF_IRQ) &= ~(PCMCIA_GPIO_CF_IRQ_MASK);
++ GPDR(PCMCIA_GPIO_CF_RESET)|= (PCMCIA_GPIO_CF_RESET_MASK);
++}
++
++inline int cerf_pcmcia_level_detect( void)
++{
++ return ((GPLR(PCMCIA_GPIO_CF_CD)&PCMCIA_GPIO_CF_CD_MASK)==0)?1:0;
++}
++inline int cerf_pcmcia_level_ready( void)
++{
++ return (GPLR(PCMCIA_GPIO_CF_IRQ)&PCMCIA_GPIO_CF_IRQ_MASK)?1:0;
++}
++inline int cerf_pcmcia_level_bvd1( void)
++{
++ return (GPLR(PCMCIA_GPIO_CF_BVD1)&PCMCIA_GPIO_CF_BVD1_MASK)?1:0;
++}
++inline int cerf_pcmcia_level_bvd2( void)
++{
++ return (GPLR(PCMCIA_GPIO_CF_BVD2)&PCMCIA_GPIO_CF_BVD2_MASK)?1:0;
++}
++
++#elif defined(CONFIG_SA1100_CERF) /* SA1100 */
++
++#define PCMCIA_GPDR GPDR
++#define PCMCIA_GPCR GPCR
++#define PCMCIA_GPSR GPSR
++#define PCMCIA_GPLR GPLR
++
++#define PCMCIA_GPIO_CF_CD_MASK GPIO_CF_CD
++#define PCMCIA_GPIO_CF_IRQ_MASK GPIO_CF_IRQ
++#define PCMCIA_GPIO_CF_RESET_MASK GPIO_CF_RESET
++#define PCMCIA_GPIO_CF_BVD1_MASK GPIO_CF_BVD1
++#define PCMCIA_GPIO_CF_BVD2_MASK GPIO_CF_BVD2
++
++#define PCMCIA_GPIO_CF_CD_EDGE PCMCIA_GPIO_CF_CD_MASK
++#define PCMCIA_GPIO_CF_IRQ_EDGE PCMCIA_GPIO_CF_IRQ_MASK
++#define PCMCIA_GPIO_CF_RESET_EDGE PCMCIA_GPIO_CF_RESET_MASK
++#define PCMCIA_GPIO_CF_BVD1_EDGE PCMCIA_GPIO_CF_BVD1_MASK
++#define PCMCIA_GPIO_CF_BVD2_EDGE PCMCIA_GPIO_CF_BVD2_MASK
++
++#define PCMCIA_IRQ_CF_CD IRQ_GPIO_CF_CD
++#define PCMCIA_IRQ_CF_IRQ IRQ_GPIO_CF_IRQ
++#define PCMCIA_IRQ_CF_BVD1 IRQ_GPIO_CF_BVD1
++#define PCMCIA_IRQ_CF_BVD2 IRQ_GPIO_CF_BVD2
++
++#define PCMCIA_PWR_SHUTDOWN GPIO_PWR_SHUTDOWN
++
++#ifdef CONFIG_SA1100_CERF_CPLD
++#define CERF_SOCKET 0
++#else
++#define CERF_SOCKET 1
++#endif
++
++inline void cerf_pcmcia_set_gpio_direction(void)
++{
++ PCMCIA_GPDR &= ~(PCMCIA_GPIO_CF_CD_MASK |
++ PCMCIA_GPIO_CF_BVD1_MASK |
++ PCMCIA_GPIO_CF_BVD2_MASK |
++ PCMCIA_GPIO_CF_IRQ_MASK);
++ PCMCIA_GPDR |= PCMCIA_GPIO_CF_RESET_MASK;
++}
++
++inline int cerf_pcmcia_level_detect( void)
++{
++ return ((PCMCIA_GPLR & PCMCIA_GPIO_CF_CD_MASK)==0)?1:0;
++}
++inline int cerf_pcmcia_level_ready( void)
++{
++ return (PCMCIA_GPLR & PCMCIA_GPIO_CF_IRQ_MASK)?1:0;
++}
++inline int cerf_pcmcia_level_bvd1( void)
++{
++ return (PCMCIA_GPLR & PCMCIA_GPIO_CF_BVD1_MASK)?1:0;
++}
++inline int cerf_pcmcia_level_bvd2( void)
++{
++ return (PCMCIA_GPLR & PCMCIA_GPIO_CF_BVD2_MASK)?1:0;
++}
++
++#endif
++
++#endif
+--- linux-2.4.27/drivers/sound/Config.in~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/sound/Config.in
+@@ -239,6 +239,7 @@
+ dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
+ fi
+ dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER
++ dep_tristate ' Intel PXA250/210 AC97 audio' CONFIG_SOUND_PXA_AC97 $CONFIG_ARCH_PXA $CONFIG_SOUND
+ fi
+
+ dep_tristate ' TV card (bt848) mixer support' CONFIG_SOUND_TVMIXER $CONFIG_SOUND $CONFIG_I2C
+--- linux-2.4.27/drivers/sound/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/sound/Makefile
+@@ -11,7 +11,7 @@
+ msnd.o opl3.o sb_common.o sequencer_syms.o \
+ sound_core.o sound_syms.o uart401.o \
+ nm256_audio.o ac97.o ac97_codec.o aci.o \
+- sa1100-audio.o
++ sa1100-audio.o pxa-audio.o pxa-ac97.o
+
+ # Each configuration option enables a list of files.
+
+@@ -85,6 +85,7 @@
+ obj-$(CONFIG_SOUND_SA1111_UDA1341) += sa1111-uda1341.o
+ obj-$(CONFIG_SOUND_SA1111_AC97) += sa1111-ac97.o ac97_codec.o
+ obj-$(CONFIG_SOUND_SA1100SSP) += sa1100ssp.o
++obj-$(CONFIG_SOUND_PXA_AC97)+= pxa-ac97.o pxa-audio.o ac97_codec.o
+ obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o
+ obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
+ obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o
+--- linux-2.4.27/drivers/sound/ac97_codec.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/sound/ac97_codec.c
+@@ -155,6 +155,7 @@
+ {0x45838308, "ESS Allegro ES1988", &null_ops},
+ {0x49434511, "ICE1232", &null_ops}, /* I hope --jk */
+ {0x4e534331, "National Semiconductor LM4549", &null_ops},
++ {0x50534304, "Philips UCB1400", &default_ops},
+ {0x53494c22, "Silicon Laboratory Si3036", &null_ops},
+ {0x53494c23, "Silicon Laboratory Si3038", &null_ops},
+ {0x545200FF, "TriTech TR?????", &tritech_m_ops},
+--- /dev/null
++++ linux-2.4.27/drivers/sound/pxa-ac97.c
+@@ -0,0 +1,370 @@
++/*
++ * linux/drivers/sound/pxa-ac97.c -- AC97 interface for the Cotula chip
++ *
++ * Author: Nicolas Pitre
++ * Created: Aug 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * AC97 GPIO Changes:-
++ * In order to read/write codec GPIO bits using AC97 link slot 12,
++ * all IO to AC97_GPIO_STATUS must be via the Xscale modem codec
++ * address space.
++ * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/poll.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++#include <linux/ac97_codec.h>
++
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++#include <asm/dma.h>
++
++#include "pxa-audio.h"
++
++static struct completion CAR_completion;
++static int waitingForMask;
++static DECLARE_MUTEX(CAR_mutex);
++
++static u16 pxa_ac97_read(struct ac97_codec *codec, u8 reg)
++{
++ u16 val = -1;
++
++ down(&CAR_mutex);
++ if (!(CAR & CAR_CAIP)) {
++ volatile u32 *reg_addr;
++
++ // if we are reading the GPIO status then this is cached
++ // in hardware so we don't need to read over the link.
++ if (reg == AC97_GPIO_STATUS) {
++ reg_addr = (u32 *)&PMC_REG_BASE + (reg >> 1);
++ val = *reg_addr;
++ return val;
++ }
++
++ reg_addr = (u32 *)&PAC_REG_BASE + (reg >> 1);
++
++ waitingForMask=GSR_SDONE;
++
++ init_completion(&CAR_completion);
++ (void)*reg_addr; //start read access across the ac97 link
++ wait_for_completion(&CAR_completion);
++
++ if (GSR & GSR_RDCS) {
++ GSR |= GSR_RDCS; //write a 1 to clear
++ printk(KERN_CRIT __FUNCTION__": read codec register timeout.\n");
++ }
++
++ init_completion(&CAR_completion);
++ val = *reg_addr; //valid data now but we've just started another cycle...
++ wait_for_completion(&CAR_completion);
++
++ } else {
++ printk(KERN_CRIT __FUNCTION__": CAR_CAIP already set\n");
++ }
++ up(&CAR_mutex);
++ //printk("%s(0x%02x) = 0x%04x\n", __FUNCTION__, reg, val);
++ return val;
++}
++
++static void pxa_ac97_write(struct ac97_codec *codec, u8 reg, u16 val)
++{
++ down(&CAR_mutex);
++ if (!(CAR & CAR_CAIP)) {
++ volatile u32 *reg_addr;
++
++ // if we are writing to the codec GPIO using slot 12
++ // then we have to write to the modem register space
++ if (reg == AC97_GPIO_STATUS) {
++ reg_addr = (u32 *)&PMC_REG_BASE + (reg >> 1);
++ *reg_addr = val;
++ return;
++ }
++
++ reg_addr = (u32 *)&PAC_REG_BASE + (reg >> 1);
++
++ waitingForMask=GSR_CDONE;
++ init_completion(&CAR_completion);
++ *reg_addr = val;
++ wait_for_completion(&CAR_completion);
++ } else {
++ printk(KERN_CRIT __FUNCTION__": CAR_CAIP already set\n");
++ }
++ up(&CAR_mutex);
++ //printk("%s(0x%02x, 0x%04x)\n", __FUNCTION__, reg, val);
++}
++
++static void pxa_ac97_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++ int gsr = GSR;
++ GSR = gsr & (GSR_SDONE|GSR_CDONE); //write a 1 to clear
++ if (gsr & waitingForMask)
++ {
++ complete(&CAR_completion);
++ }
++}
++
++static struct ac97_codec pxa_ac97_codec = {
++ codec_read: pxa_ac97_read,
++ codec_write: pxa_ac97_write,
++};
++
++static DECLARE_MUTEX(pxa_ac97_mutex);
++static int pxa_ac97_refcount;
++
++int pxa_ac97_get(struct ac97_codec **codec)
++{
++ int ret;
++
++ *codec = NULL;
++ down(&pxa_ac97_mutex);
++
++ if (!pxa_ac97_refcount) {
++ ret = request_irq(IRQ_AC97, pxa_ac97_irq, 0, "AC97", NULL);
++ if (ret)
++ return ret;
++
++ CKEN |= CKEN2_AC97;
++ set_GPIO_mode(GPIO31_SYNC_AC97_MD);
++ set_GPIO_mode(GPIO30_SDATA_OUT_AC97_MD);
++ set_GPIO_mode(GPIO28_BITCLK_AC97_MD);
++ set_GPIO_mode(GPIO29_SDATA_IN_AC97_MD);
++
++ GCR = 0;
++ udelay(10);
++ GCR = GCR_COLD_RST|GCR_CDONE_IE|GCR_SDONE_IE;
++ while (!(GSR & GSR_PCR)) {
++ schedule();
++ }
++
++ ret = ac97_probe_codec(&pxa_ac97_codec);
++ if (ret != 1) {
++ free_irq(IRQ_AC97, NULL);
++ GCR = GCR_ACLINK_OFF;
++ CKEN &= ~CKEN2_AC97;
++ return ret;
++ }
++
++ // need little hack for UCB1400 (should be moved elsewhere)
++ pxa_ac97_write(&pxa_ac97_codec,AC97_EXTENDED_STATUS,1);
++ //pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x1ff7);
++ pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x0050);
++ pxa_ac97_write(&pxa_ac97_codec, 0x6c, 0x0030);
++ }
++
++ pxa_ac97_refcount++;
++ up(&pxa_ac97_mutex);
++ *codec = &pxa_ac97_codec;
++ return 0;
++}
++
++void pxa_ac97_put(void)
++{
++ down(&pxa_ac97_mutex);
++ pxa_ac97_refcount--;
++ if (!pxa_ac97_refcount) {
++ GCR = GCR_ACLINK_OFF;
++ CKEN &= ~CKEN2_AC97;
++ free_irq(IRQ_AC97, NULL);
++ }
++ up(&pxa_ac97_mutex);
++}
++
++EXPORT_SYMBOL(pxa_ac97_get);
++EXPORT_SYMBOL(pxa_ac97_put);
++
++
++/*
++ * Audio Mixer stuff
++ */
++
++static audio_state_t ac97_audio_state;
++static audio_stream_t ac97_audio_in;
++
++static int mixer_ioctl( struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ int ret, val;
++
++ ret = pxa_ac97_codec.mixer_ioctl(&pxa_ac97_codec, cmd, arg);
++ if (ret)
++ return ret;
++
++ /* We must snoop for some commands to provide our own extra processing */
++ switch (cmd) {
++ case SOUND_MIXER_WRITE_RECSRC:
++ /*
++ * According to the PXA250 spec, mic-in should use different
++ * DRCMR and different AC97 FIFO.
++ * Unfortunately current UCB1400 versions (up to ver 2A) don't
++ * produce slot 6 for the audio input frame, therefore the PXA
++ * AC97 mic-in FIFO is always starved.
++ */
++#if 0
++ ret = get_user(val, (int *)arg);
++ if (ret)
++ return ret;
++ pxa_audio_clear_buf(&ac97_audio_in);
++ *ac97_audio_in.drcmr = 0;
++ if (val & (1 << SOUND_MIXER_MIC)) {
++ ac97_audio_in.dcmd = DCMD_RXMCDR;
++ ac97_audio_in.drcmr = &DRCMRRXMCDR;
++ ac97_audio_in.dev_addr = __PREG(MCDR);
++ } else {
++ ac97_audio_in.dcmd = DCMD_RXPCDR;
++ ac97_audio_in.drcmr = &DRCMRRXPCDR;
++ ac97_audio_in.dev_addr = __PREG(PCDR);
++ }
++ if (ac97_audio_state.rd_ref)
++ *ac97_audio_in.drcmr =
++ ac97_audio_in.dma_ch | DRCMR_MAPVLD;
++#endif
++ break;
++ }
++ return 0;
++}
++
++static struct file_operations mixer_fops = {
++ ioctl: mixer_ioctl,
++ llseek: no_llseek,
++ owner: THIS_MODULE
++};
++
++/*
++ * AC97 codec ioctls
++ */
++
++static int codec_adc_rate = 48000;
++static int codec_dac_rate = 48000;
++
++static int ac97_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ int ret;
++ long val;
++
++ switch(cmd) {
++ case SNDCTL_DSP_STEREO:
++ ret = get_user(val, (int *) arg);
++ if (ret)
++ return ret;
++ /* FIXME: do we support mono? */
++ ret = (val == 0) ? -EINVAL : 1;
++ return put_user(ret, (int *) arg);
++
++ case SNDCTL_DSP_CHANNELS:
++ case SOUND_PCM_READ_CHANNELS:
++ /* FIXME: do we support mono? */
++ return put_user(2, (long *) arg);
++
++ case SNDCTL_DSP_SPEED:
++ ret = get_user(val, (long *) arg);
++ if (ret)
++ return ret;
++ if (file->f_mode & FMODE_READ)
++ codec_adc_rate = ac97_set_adc_rate(&pxa_ac97_codec, val);
++ if (file->f_mode & FMODE_WRITE)
++ codec_dac_rate = ac97_set_dac_rate(&pxa_ac97_codec, val);
++ /* fall through */
++
++ case SOUND_PCM_READ_RATE:
++ if (file->f_mode & FMODE_READ)
++ val = codec_adc_rate;
++ if (file->f_mode & FMODE_WRITE)
++ val = codec_dac_rate;
++ return put_user(val, (long *) arg);
++
++ case SNDCTL_DSP_SETFMT:
++ case SNDCTL_DSP_GETFMTS:
++ /* FIXME: can we do other fmts? */
++ return put_user(AFMT_S16_LE, (long *) arg);
++
++ default:
++ /* Maybe this is meant for the mixer (As per OSS Docs) */
++ return mixer_ioctl(inode, file, cmd, arg);
++ }
++ return 0;
++}
++
++
++/*
++ * Audio stuff
++ */
++
++static audio_stream_t ac97_audio_out = {
++ name: "AC97 audio out",
++ dcmd: DCMD_TXPCDR,
++ drcmr: &DRCMRTXPCDR,
++ dev_addr: __PREG(PCDR),
++};
++
++static audio_stream_t ac97_audio_in = {
++ name: "AC97 audio in",
++ dcmd: DCMD_RXPCDR,
++ drcmr: &DRCMRRXPCDR,
++ dev_addr: __PREG(PCDR),
++};
++
++static audio_state_t ac97_audio_state = {
++ output_stream: &ac97_audio_out,
++ input_stream: &ac97_audio_in,
++ client_ioctl: ac97_ioctl,
++ sem: __MUTEX_INITIALIZER(ac97_audio_state.sem),
++};
++
++static int ac97_audio_open(struct inode *inode, struct file *file)
++{
++ return pxa_audio_attach(inode, file, &ac97_audio_state);
++}
++
++/*
++ * Missing fields of this structure will be patched with the call
++ * to pxa_audio_attach().
++ */
++
++static struct file_operations ac97_audio_fops = {
++ open: ac97_audio_open,
++ owner: THIS_MODULE
++};
++
++
++static int __init pxa_ac97_init(void)
++{
++ int ret;
++ struct ac97_codec *dummy;
++
++ ret = pxa_ac97_get(&dummy);
++ if (ret)
++ return ret;
++
++ ac97_audio_state.dev_dsp = register_sound_dsp(&ac97_audio_fops, -1);
++ pxa_ac97_codec.dev_mixer = register_sound_mixer(&mixer_fops, -1);
++
++ return 0;
++}
++
++static void __exit pxa_ac97_exit(void)
++{
++ unregister_sound_dsp(ac97_audio_state.dev_dsp);
++ unregister_sound_mixer(pxa_ac97_codec.dev_mixer);
++ pxa_ac97_put();
++}
++
++
++module_init(pxa_ac97_init);
++module_exit(pxa_ac97_exit);
++
+--- /dev/null
++++ linux-2.4.27/drivers/sound/pxa-audio.c
+@@ -0,0 +1,853 @@
++/*
++ * linux/drivers/sound/pxa-audio.c -- audio interface for the Cotula chip
++ *
++ * Author: Nicolas Pitre
++ * Created: Aug 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/poll.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++#include <asm/dma.h>
++
++#include "pxa-audio.h"
++
++
++#define AUDIO_NBFRAGS_DEFAULT 8
++#define AUDIO_FRAGSIZE_DEFAULT 8192
++
++#define MAX_DMA_SIZE 4096
++#define DMA_DESC_SIZE sizeof(pxa_dma_desc)
++
++
++/*
++ * This function frees all buffers
++ */
++#define audio_clear_buf pxa_audio_clear_buf
++
++void pxa_audio_clear_buf(audio_stream_t * s)
++{
++ DECLARE_WAITQUEUE(wait, current);
++ int frag;
++
++ if (!s->buffers)
++ return;
++
++ /* Ensure DMA isn't running */
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ add_wait_queue(&s->stop_wq, &wait);
++ DCSR(s->dma_ch) = DCSR_STOPIRQEN;
++ schedule();
++ remove_wait_queue(&s->stop_wq, &wait);
++
++ /* free DMA buffers */
++ for (frag = 0; frag < s->nbfrags; frag++) {
++ audio_buf_t *b = &s->buffers[frag];
++ if (!b->master)
++ continue;
++ consistent_free(b->data, b->master, b->dma_desc->dsadr);
++ }
++
++ /* free descriptor ring */
++ if (s->buffers->dma_desc)
++ consistent_free(s->buffers->dma_desc,
++ s->nbfrags * s->descs_per_frag * DMA_DESC_SIZE,
++ s->dma_desc_phys);
++
++ /* free buffer structure array */
++ kfree(s->buffers);
++ s->buffers = NULL;
++}
++
++/*
++ * This function allocates the DMA descriptor array and buffer data space
++ * according to the current number of fragments and fragment size.
++ */
++static int audio_setup_buf(audio_stream_t * s)
++{
++ pxa_dma_desc *dma_desc;
++ dma_addr_t dma_desc_phys;
++ int nb_desc, frag, i, buf_size = 0;
++ char *dma_buf = NULL;
++ dma_addr_t dma_buf_phys = 0;
++
++ if (s->buffers)
++ return -EBUSY;
++
++ /* Our buffer structure array */
++ s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
++ if (!s->buffers)
++ goto err;
++ memzero(s->buffers, sizeof(audio_buf_t) * s->nbfrags);
++
++ /*
++ * Our DMA descriptor array:
++ * for Each fragment we have one checkpoint descriptor plus one
++ * descriptor per MAX_DMA_SIZE byte data blocks.
++ */
++ nb_desc = (1 + (s->fragsize + MAX_DMA_SIZE - 1)/MAX_DMA_SIZE) * s->nbfrags;
++ dma_desc = consistent_alloc(GFP_KERNEL,
++ nb_desc * DMA_DESC_SIZE,
++ &dma_desc_phys,
++ 0);
++ if (!dma_desc)
++ goto err;
++ s->descs_per_frag = nb_desc / s->nbfrags;
++ s->buffers->dma_desc = dma_desc;
++ s->dma_desc_phys = dma_desc_phys;
++ for (i = 0; i < nb_desc - 1; i++)
++ dma_desc[i].ddadr = dma_desc_phys + (i + 1) * DMA_DESC_SIZE;
++ dma_desc[i].ddadr = dma_desc_phys;
++
++ /* Our actual DMA buffers */
++ for (frag = 0; frag < s->nbfrags; frag++) {
++ audio_buf_t *b = &s->buffers[frag];
++
++ /*
++ * Let's allocate non-cached memory for DMA buffers.
++ * We try to allocate all memory at once.
++ * If this fails (a common reason is memory fragmentation),
++ * then we'll try allocating smaller buffers.
++ */
++ if (!buf_size) {
++ buf_size = (s->nbfrags - frag) * s->fragsize;
++ do {
++ dma_buf = consistent_alloc(GFP_KERNEL,
++ buf_size,
++ &dma_buf_phys,
++ 0);
++ if (!dma_buf)
++ buf_size -= s->fragsize;
++ } while (!dma_buf && buf_size);
++ if (!dma_buf)
++ goto err;
++ b->master = buf_size;
++ memzero(dma_buf, buf_size);
++ }
++
++ /*
++ * Set up our checkpoint descriptor. Since the count
++ * is always zero, we'll abuse the dsadr and dtadr fields
++ * just in case this one is picked up by the hardware
++ * while processing SOUND_DSP_GETPTR.
++ */
++ dma_desc->dsadr = dma_buf_phys;
++ dma_desc->dtadr = dma_buf_phys;
++ dma_desc->dcmd = DCMD_ENDIRQEN;
++ if (s->output && !s->mapped)
++ dma_desc->ddadr |= DDADR_STOP;
++ b->dma_desc = dma_desc++;
++
++ /* set up the actual data descriptors */
++ for (i = 0; (i * MAX_DMA_SIZE) < s->fragsize; i++) {
++ dma_desc[i].dsadr = (s->output) ?
++ (dma_buf_phys + i*MAX_DMA_SIZE) : s->dev_addr;
++ dma_desc[i].dtadr = (s->output) ?
++ s->dev_addr : (dma_buf_phys + i*MAX_DMA_SIZE);
++ dma_desc[i].dcmd = s->dcmd |
++ ((s->fragsize < MAX_DMA_SIZE) ?
++ s->fragsize : MAX_DMA_SIZE);
++ }
++ dma_desc += i;
++
++ /* handle buffer pointers */
++ b->data = dma_buf;
++ dma_buf += s->fragsize;
++ dma_buf_phys += s->fragsize;
++ buf_size -= s->fragsize;
++ }
++
++ s->usr_frag = s->dma_frag = 0;
++ s->bytecount = 0;
++ s->fragcount = 0;
++ sema_init(&s->sem, (s->output) ? s->nbfrags : 0);
++ return 0;
++
++err:
++ printk("pxa-audio: unable to allocate audio memory\n ");
++ audio_clear_buf(s);
++ return -ENOMEM;
++}
++
++/*
++ * Our DMA interrupt handler
++ */
++static void audio_dma_irq(int ch, void *dev_id, struct pt_regs *regs)
++{
++ audio_stream_t *s = dev_id;
++ u_int dcsr;
++
++ dcsr = DCSR(ch);
++ DCSR(ch) = dcsr & ~DCSR_STOPIRQEN;
++
++ if (!s->buffers) {
++ printk("AC97 DMA: wow... received IRQ for channel %d but no buffer exists\n", ch);
++ return;
++ }
++
++ if (dcsr & DCSR_BUSERR)
++ printk("AC97 DMA: bus error interrupt on channel %d\n", ch);
++
++ if (dcsr & DCSR_ENDINTR) {
++ u_long cur_dma_desc;
++ u_int cur_dma_frag;
++
++ /*
++ * Find out which DMA desc is current. Note that DDADR
++ * points to the next desc, not the current one.
++ */
++ cur_dma_desc = DDADR(ch) - s->dma_desc_phys - DMA_DESC_SIZE;
++
++ /*
++ * Let the compiler nicely optimize constant divisors into
++ * multiplications for the common cases which is much faster.
++ * Common cases: x = 1 + (1 << y) for y = [0..3]
++ */
++ switch (s->descs_per_frag) {
++ case 2: cur_dma_frag = cur_dma_desc / (2*DMA_DESC_SIZE); break;
++ case 3: cur_dma_frag = cur_dma_desc / (3*DMA_DESC_SIZE); break;
++ case 5: cur_dma_frag = cur_dma_desc / (5*DMA_DESC_SIZE); break;
++ case 9: cur_dma_frag = cur_dma_desc / (9*DMA_DESC_SIZE); break;
++ default: cur_dma_frag =
++ cur_dma_desc / (s->descs_per_frag * DMA_DESC_SIZE);
++ }
++
++ /* Account for possible wrap back of cur_dma_desc above */
++ if (cur_dma_frag >= s->nbfrags)
++ cur_dma_frag = s->nbfrags - 1;
++
++ while (s->dma_frag != cur_dma_frag) {
++ if (!s->mapped) {
++ /*
++ * This fragment is done - set the checkpoint
++ * descriptor to STOP until it is gets
++ * processed by the read or write function.
++ */
++ s->buffers[s->dma_frag].dma_desc->ddadr |= DDADR_STOP;
++ up(&s->sem);
++ }
++ if (++s->dma_frag >= s->nbfrags)
++ s->dma_frag = 0;
++
++ /* Accounting */
++ s->bytecount += s->fragsize;
++ s->fragcount++;
++ }
++
++ /* ... and for polling processes */
++ wake_up(&s->frag_wq);
++ }
++
++ if ((dcsr & DCSR_STOPIRQEN) && (dcsr & DCSR_STOPSTATE))
++ wake_up(&s->stop_wq);
++}
++
++/*
++ * Validate and sets up buffer fragments, etc.
++ */
++static int audio_set_fragments(audio_stream_t *s, int val)
++{
++ if (s->mapped || DCSR(s->dma_ch) & DCSR_RUN)
++ return -EBUSY;
++ if (s->buffers)
++ audio_clear_buf(s);
++ s->nbfrags = (val >> 16) & 0x7FFF;
++ val &= 0xffff;
++ if (val < 5)
++ val = 5;
++ if (val > 15)
++ val = 15;
++ s->fragsize = 1 << val;
++ if (s->nbfrags < 2)
++ s->nbfrags = 2;
++ if (s->nbfrags * s->fragsize > 256 * 1024)
++ s->nbfrags = 256 * 1024 / s->fragsize;
++ if (audio_setup_buf(s))
++ return -ENOMEM;
++ return val|(s->nbfrags << 16);
++}
++
++
++/*
++ * The fops functions
++ */
++
++static int audio_write(struct file *file, const char *buffer,
++ size_t count, loff_t * ppos)
++{
++ const char *buffer0 = buffer;
++ audio_state_t *state = (audio_state_t *)file->private_data;
++ audio_stream_t *s = state->output_stream;
++ int chunksize, ret = 0;
++
++ if (ppos != &file->f_pos)
++ return -ESPIPE;
++ if (s->mapped)
++ return -ENXIO;
++ if (!s->buffers && audio_setup_buf(s))
++ return -ENOMEM;
++
++ while (count > 0) {
++ audio_buf_t *b = &s->buffers[s->usr_frag];
++
++ /* Grab a fragment */
++ if (file->f_flags & O_NONBLOCK) {
++ ret = -EAGAIN;
++ if (down_trylock(&s->sem))
++ break;
++ } else {
++ ret = -ERESTARTSYS;
++ if (down_interruptible(&s->sem))
++ break;
++ }
++
++ /* Feed the current buffer */
++ chunksize = s->fragsize - b->offset;
++ if (chunksize > count)
++ chunksize = count;
++ if (copy_from_user(b->data + b->offset, buffer, chunksize)) {
++ up(&s->sem);
++ return -EFAULT;
++ }
++ b->offset += chunksize;
++ buffer += chunksize;
++ count -= chunksize;
++ if (b->offset < s->fragsize) {
++ up(&s->sem);
++ break;
++ }
++
++ /*
++ * Activate DMA on current buffer.
++ * We unlock this fragment's checkpoint descriptor and
++ * kick DMA if it is idle. Using checkpoint descriptors
++ * allows for control operations without the need for
++ * stopping the DMA channel if it is already running.
++ */
++ b->offset = 0;
++ b->dma_desc->ddadr &= ~DDADR_STOP;
++ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
++ DDADR(s->dma_ch) = b->dma_desc->ddadr;
++ DCSR(s->dma_ch) = DCSR_RUN;
++ }
++
++ /* move the index to the next fragment */
++ if (++s->usr_frag >= s->nbfrags)
++ s->usr_frag = 0;
++ }
++
++ if ((buffer - buffer0))
++ ret = buffer - buffer0;
++ return ret;
++}
++
++
++static int audio_read(struct file *file, char *buffer,
++ size_t count, loff_t * ppos)
++{
++ char *buffer0 = buffer;
++ audio_state_t *state = file->private_data;
++ audio_stream_t *s = state->input_stream;
++ int chunksize, ret = 0;
++
++ if (ppos != &file->f_pos)
++ return -ESPIPE;
++ if (s->mapped)
++ return -ENXIO;
++ if (!s->buffers && audio_setup_buf(s))
++ return -ENOMEM;
++
++ while (count > 0) {
++ audio_buf_t *b = &s->buffers[s->usr_frag];
++
++ /* prime DMA */
++ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
++ DDADR(s->dma_ch) =
++ s->buffers[s->dma_frag].dma_desc->ddadr;
++ DCSR(s->dma_ch) = DCSR_RUN;
++ }
++
++ /* Wait for a buffer to become full */
++ if (file->f_flags & O_NONBLOCK) {
++ ret = -EAGAIN;
++ if (down_trylock(&s->sem))
++ break;
++ } else {
++ ret = -ERESTARTSYS;
++ if (down_interruptible(&s->sem))
++ break;
++ }
++
++ /* Grab data from current buffer */
++ chunksize = s->fragsize - b->offset;
++ if (chunksize > count)
++ chunksize = count;
++ if (copy_to_user(buffer, b->data + b->offset, chunksize)) {
++ up(&s->sem);
++ return -EFAULT;
++ }
++ b->offset += chunksize;
++ buffer += chunksize;
++ count -= chunksize;
++ if (b->offset < s->fragsize) {
++ up(&s->sem);
++ break;
++ }
++
++ /*
++ * Make this buffer available for DMA again.
++ * We unlock this fragment's checkpoint descriptor and
++ * kick DMA if it is idle. Using checkpoint descriptors
++ * allows for control operations without the need for
++ * stopping the DMA channel if it is already running.
++ */
++ b->offset = 0;
++ b->dma_desc->ddadr &= ~DDADR_STOP;
++
++ /* move the index to the next fragment */
++ if (++s->usr_frag >= s->nbfrags)
++ s->usr_frag = 0;
++ }
++
++ if ((buffer - buffer0))
++ ret = buffer - buffer0;
++ return ret;
++}
++
++
++static int audio_sync(struct file *file)
++{
++ audio_state_t *state = file->private_data;
++ audio_stream_t *s = state->output_stream;
++ audio_buf_t *b;
++ pxa_dma_desc *final_desc;
++ u_long dcmd_save = 0;
++ DECLARE_WAITQUEUE(wait, current);
++
++ if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped)
++ return 0;
++
++ /*
++ * Send current buffer if it contains data. Be sure to send
++ * a full sample count.
++ */
++ final_desc = NULL;
++ b = &s->buffers[s->usr_frag];
++ if (b->offset &= ~3) {
++ final_desc = &b->dma_desc[1 + b->offset/MAX_DMA_SIZE];
++ b->offset &= (MAX_DMA_SIZE-1);
++ dcmd_save = final_desc->dcmd;
++ final_desc->dcmd = b->offset | s->dcmd | DCMD_ENDIRQEN;
++ final_desc->ddadr |= DDADR_STOP;
++ b->offset = 0;
++ b->dma_desc->ddadr &= ~DDADR_STOP;
++ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
++ DDADR(s->dma_ch) = b->dma_desc->ddadr;
++ DCSR(s->dma_ch) = DCSR_RUN;
++ }
++ }
++
++ /* Wait for DMA to complete. */
++ set_current_state(TASK_INTERRUPTIBLE);
++#if 0
++ /*
++ * The STOPSTATE IRQ never seem to occur if DCSR_STOPIRQEN is set
++ * along wotj DCSR_RUN. Silicon bug?
++ */
++ add_wait_queue(&s->stop_wq, &wait);
++ DCSR(s->dma_ch) |= DCSR_STOPIRQEN;
++ schedule();
++#else
++ add_wait_queue(&s->frag_wq, &wait);
++ while ((DCSR(s->dma_ch) & DCSR_RUN) && !signal_pending(current)) {
++ schedule();
++ set_current_state(TASK_INTERRUPTIBLE);
++ }
++#endif
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&s->frag_wq, &wait);
++
++ /* Restore the descriptor chain. */
++ if (final_desc) {
++ final_desc->dcmd = dcmd_save;
++ final_desc->ddadr &= ~DDADR_STOP;
++ b->dma_desc->ddadr |= DDADR_STOP;
++ }
++ return 0;
++}
++
++
++static unsigned int audio_poll(struct file *file,
++ struct poll_table_struct *wait)
++{
++ audio_state_t *state = file->private_data;
++ audio_stream_t *is = state->input_stream;
++ audio_stream_t *os = state->output_stream;
++ unsigned int mask = 0;
++
++ if (file->f_mode & FMODE_READ) {
++ /* Start audio input if not already active */
++ if (!is->buffers && audio_setup_buf(is))
++ return -ENOMEM;
++ if (DCSR(is->dma_ch) & DCSR_STOPSTATE) {
++ DDADR(is->dma_ch) =
++ is->buffers[is->dma_frag].dma_desc->ddadr;
++ DCSR(is->dma_ch) = DCSR_RUN;
++ }
++ poll_wait(file, &is->frag_wq, wait);
++ }
++
++ if (file->f_mode & FMODE_WRITE) {
++ if (!os->buffers && audio_setup_buf(os))
++ return -ENOMEM;
++ poll_wait(file, &os->frag_wq, wait);
++ }
++
++ if (file->f_mode & FMODE_READ)
++ if (( is->mapped && is->bytecount > 0) ||
++ (!is->mapped && atomic_read(&is->sem.count) > 0))
++ mask |= POLLIN | POLLRDNORM;
++
++ if (file->f_mode & FMODE_WRITE)
++ if (( os->mapped && os->bytecount > 0) ||
++ (!os->mapped && atomic_read(&os->sem.count) > 0))
++ mask |= POLLOUT | POLLWRNORM;
++
++ return mask;
++}
++
++
++static int audio_ioctl( struct inode *inode, struct file *file,
++ uint cmd, ulong arg)
++{
++ audio_state_t *state = file->private_data;
++ audio_stream_t *os = state->output_stream;
++ audio_stream_t *is = state->input_stream;
++ long val;
++
++ switch (cmd) {
++ case OSS_GETVERSION:
++ return put_user(SOUND_VERSION, (int *)arg);
++
++ case SNDCTL_DSP_GETBLKSIZE:
++ if (file->f_mode & FMODE_WRITE)
++ return put_user(os->fragsize, (int *)arg);
++ else
++ return put_user(is->fragsize, (int *)arg);
++
++ case SNDCTL_DSP_GETCAPS:
++ val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP;
++ if (is && os)
++ val |= DSP_CAP_DUPLEX;
++ return put_user(val, (int *)arg);
++
++ case SNDCTL_DSP_SETFRAGMENT:
++ if (get_user(val, (long *) arg))
++ return -EFAULT;
++ if (file->f_mode & FMODE_READ) {
++ int ret = audio_set_fragments(is, val);
++ if (ret < 0)
++ return ret;
++ ret = put_user(ret, (int *)arg);
++ if (ret)
++ return ret;
++ }
++ if (file->f_mode & FMODE_WRITE) {
++ int ret = audio_set_fragments(os, val);
++ if (ret < 0)
++ return ret;
++ ret = put_user(ret, (int *)arg);
++ if (ret)
++ return ret;
++ }
++ return 0;
++
++ case SNDCTL_DSP_SYNC:
++ return audio_sync(file);
++
++ case SNDCTL_DSP_SETDUPLEX:
++ return 0;
++
++ case SNDCTL_DSP_POST:
++ return 0;
++
++ case SNDCTL_DSP_GETTRIGGER:
++ val = 0;
++ if (file->f_mode & FMODE_READ && DCSR(is->dma_ch) & DCSR_RUN)
++ val |= PCM_ENABLE_INPUT;
++ if (file->f_mode & FMODE_WRITE && DCSR(os->dma_ch) & DCSR_RUN)
++ val |= PCM_ENABLE_OUTPUT;
++ return put_user(val, (int *)arg);
++
++ case SNDCTL_DSP_SETTRIGGER:
++ if (get_user(val, (int *)arg))
++ return -EFAULT;
++ if (file->f_mode & FMODE_READ) {
++ if (val & PCM_ENABLE_INPUT) {
++ if (!is->buffers && audio_setup_buf(is))
++ return -ENOMEM;
++ if (!(DCSR(is->dma_ch) & DCSR_RUN)) {
++ audio_buf_t *b = &is->buffers[is->dma_frag];
++ DDADR(is->dma_ch) = b->dma_desc->ddadr;
++ DCSR(is->dma_ch) = DCSR_RUN;
++ }
++ } else {
++ DCSR(is->dma_ch) = 0;
++ }
++ }
++ if (file->f_mode & FMODE_WRITE) {
++ if (val & PCM_ENABLE_OUTPUT) {
++ if (!os->buffers && audio_setup_buf(os))
++ return -ENOMEM;
++ if (!(DCSR(os->dma_ch) & DCSR_RUN)) {
++ audio_buf_t *b = &os->buffers[os->dma_frag];
++ DDADR(os->dma_ch) = b->dma_desc->ddadr;
++ DCSR(os->dma_ch) = DCSR_RUN;
++ }
++ } else {
++ DCSR(os->dma_ch) = 0;
++ }
++ }
++ return 0;
++
++ case SNDCTL_DSP_GETOSPACE:
++ case SNDCTL_DSP_GETISPACE:
++ {
++ audio_buf_info inf = { 0, };
++ audio_stream_t *s = (cmd == SNDCTL_DSP_GETOSPACE) ? os : is;
++
++ if ((s == is && !(file->f_mode & FMODE_READ)) ||
++ (s == os && !(file->f_mode & FMODE_WRITE)))
++ return -EINVAL;
++ if (!s->buffers && audio_setup_buf(s))
++ return -ENOMEM;
++ inf.bytes = atomic_read(&s->sem.count) * s->fragsize;
++ inf.bytes -= s->buffers[s->usr_frag].offset;
++ inf.fragments = inf.bytes / s->fragsize;
++ inf.fragsize = s->fragsize;
++ inf.fragstotal = s->nbfrags;
++ return copy_to_user((void *)arg, &inf, sizeof(inf));
++ }
++
++ case SNDCTL_DSP_GETOPTR:
++ case SNDCTL_DSP_GETIPTR:
++ {
++ count_info inf = { 0, };
++ audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is;
++ dma_addr_t ptr;
++ int bytecount, offset, flags;
++
++ if ((s == is && !(file->f_mode & FMODE_READ)) ||
++ (s == os && !(file->f_mode & FMODE_WRITE)))
++ return -EINVAL;
++ if (DCSR(s->dma_ch) & DCSR_RUN) {
++ audio_buf_t *b;
++ save_flags_cli(flags);
++ ptr = (s->output) ? DSADR(s->dma_ch) : DTADR(s->dma_ch);
++ b = &s->buffers[s->dma_frag];
++ offset = ptr - b->dma_desc->dsadr;
++ if (offset >= s->fragsize)
++ offset = s->fragsize - 4;
++ } else {
++ save_flags(flags);
++ offset = 0;
++ }
++ inf.ptr = s->dma_frag * s->fragsize + offset;
++ bytecount = s->bytecount + offset;
++ s->bytecount = -offset;
++ inf.blocks = s->fragcount;
++ s->fragcount = 0;
++ restore_flags(flags);
++ if (bytecount < 0)
++ bytecount = 0;
++ inf.bytes = bytecount;
++ return copy_to_user((void *)arg, &inf, sizeof(inf));
++ }
++
++ case SNDCTL_DSP_NONBLOCK:
++ file->f_flags |= O_NONBLOCK;
++ return 0;
++
++ case SNDCTL_DSP_RESET:
++ if (file->f_mode & FMODE_WRITE)
++ audio_clear_buf(os);
++ if (file->f_mode & FMODE_READ)
++ audio_clear_buf(is);
++ return 0;
++
++ default:
++ return state->client_ioctl(inode, file, cmd, arg);
++ }
++
++ return 0;
++}
++
++
++static int audio_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ audio_state_t *state = file->private_data;
++ audio_stream_t *s;
++ unsigned long size, vma_addr;
++ int i, ret;
++
++ if (vma->vm_pgoff != 0)
++ return -EINVAL;
++
++ if (vma->vm_flags & VM_WRITE) {
++ if (!state->wr_ref)
++ return -EINVAL;;
++ s = state->output_stream;
++ } else if (vma->vm_flags & VM_READ) {
++ if (!state->rd_ref)
++ return -EINVAL;
++ s = state->input_stream;
++ } else return -EINVAL;
++
++ if (s->mapped)
++ return -EINVAL;
++ size = vma->vm_end - vma->vm_start;
++ if (size != s->fragsize * s->nbfrags)
++ return -EINVAL;
++ if (!s->buffers && audio_setup_buf(s))
++ return -ENOMEM;
++ vma_addr = vma->vm_start;
++ for (i = 0; i < s->nbfrags; i++) {
++ audio_buf_t *buf = &s->buffers[i];
++ if (!buf->master)
++ continue;
++ ret = remap_page_range(vma_addr, buf->dma_desc->dsadr,
++ buf->master, vma->vm_page_prot);
++ if (ret)
++ return ret;
++ vma_addr += buf->master;
++ }
++ for (i = 0; i < s->nbfrags; i++)
++ s->buffers[i].dma_desc->ddadr &= ~DDADR_STOP;
++ s->mapped = 1;
++ return 0;
++}
++
++
++static int audio_release(struct inode *inode, struct file *file)
++{
++ audio_state_t *state = file->private_data;
++
++ down(&state->sem);
++
++ if (file->f_mode & FMODE_READ) {
++ audio_clear_buf(state->input_stream);
++ *state->input_stream->drcmr = 0;
++ pxa_free_dma(state->input_stream->dma_ch);
++ state->rd_ref = 0;
++ }
++
++ if (file->f_mode & FMODE_WRITE) {
++ audio_sync(file);
++ audio_clear_buf(state->output_stream);
++ *state->output_stream->drcmr = 0;
++ pxa_free_dma(state->output_stream->dma_ch);
++ state->wr_ref = 0;
++ }
++
++ up(&state->sem);
++ return 0;
++}
++
++
++int pxa_audio_attach(struct inode *inode, struct file *file,
++ audio_state_t *state)
++{
++ audio_stream_t *is = state->input_stream;
++ audio_stream_t *os = state->output_stream;
++ int err;
++
++ down(&state->sem);
++
++ /* access control */
++ err = -ENODEV;
++ if ((file->f_mode & FMODE_WRITE) && !os)
++ goto out;
++ if ((file->f_mode & FMODE_READ) && !is)
++ goto out;
++ err = -EBUSY;
++ if ((file->f_mode & FMODE_WRITE) && state->wr_ref)
++ goto out;
++ if ((file->f_mode & FMODE_READ) && state->rd_ref)
++ goto out;
++
++ /* request DMA channels */
++ if (file->f_mode & FMODE_WRITE) {
++ err = pxa_request_dma(os->name, DMA_PRIO_LOW,
++ audio_dma_irq, os);
++ if (err < 0)
++ goto out;
++ os->dma_ch = err;
++ }
++ if (file->f_mode & FMODE_READ) {
++ err = pxa_request_dma(is->name, DMA_PRIO_LOW,
++ audio_dma_irq, is);
++ if (err < 0) {
++ if (file->f_mode & FMODE_WRITE) {
++ *os->drcmr = 0;
++ pxa_free_dma(os->dma_ch);
++ }
++ goto out;
++ }
++ is->dma_ch = err;
++ }
++
++ file->private_data = state;
++ file->f_op->release = audio_release;
++ file->f_op->write = audio_write;
++ file->f_op->read = audio_read;
++ file->f_op->mmap = audio_mmap;
++ file->f_op->poll = audio_poll;
++ file->f_op->ioctl = audio_ioctl;
++ file->f_op->llseek = no_llseek;
++
++ if ((file->f_mode & FMODE_WRITE)) {
++ state->wr_ref = 1;
++ os->fragsize = AUDIO_FRAGSIZE_DEFAULT;
++ os->nbfrags = AUDIO_NBFRAGS_DEFAULT;
++ os->output = 1;
++ os->mapped = 0;
++ init_waitqueue_head(&os->frag_wq);
++ init_waitqueue_head(&os->stop_wq);
++ *os->drcmr = os->dma_ch | DRCMR_MAPVLD;
++ }
++ if (file->f_mode & FMODE_READ) {
++ state->rd_ref = 1;
++ is->fragsize = AUDIO_FRAGSIZE_DEFAULT;
++ is->nbfrags = AUDIO_NBFRAGS_DEFAULT;
++ is->output = 0;
++ is->mapped = 0;
++ init_waitqueue_head(&is->frag_wq);
++ init_waitqueue_head(&is->stop_wq);
++ *is->drcmr = is->dma_ch | DRCMR_MAPVLD;
++ }
++
++ err = 0;
++
++out:
++ up(&state->sem);
++ return err;
++}
++
++EXPORT_SYMBOL(pxa_audio_attach);
++EXPORT_SYMBOL(pxa_audio_clear_buf);
++
+--- /dev/null
++++ linux-2.4.27/drivers/sound/pxa-audio.h
+@@ -0,0 +1,55 @@
++/*
++ * linux/drivers/sound/pxa-audio.h -- audio interface for the Cotula chip
++ *
++ * Author: Nicolas Pitre
++ * Created: Aug 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++typedef struct {
++ int offset; /* current buffer position */
++ char *data; /* actual buffer */
++ pxa_dma_desc *dma_desc; /* pointer to the starting desc */
++ int master; /* owner for buffer allocation, contain size whn true */
++} audio_buf_t;
++
++typedef struct {
++ char *name; /* stream identifier */
++ audio_buf_t *buffers; /* pointer to audio buffer array */
++ u_int usr_frag; /* user fragment index */
++ u_int dma_frag; /* DMA fragment index */
++ u_int fragsize; /* fragment size */
++ u_int nbfrags; /* number of fragments */
++ u_int dma_ch; /* DMA channel number */
++ dma_addr_t dma_desc_phys; /* phys addr of descriptor ring */
++ u_int descs_per_frag; /* nbr descriptors per fragment */
++ int bytecount; /* nbr of processed bytes */
++ int fragcount; /* nbr of fragment transitions */
++ struct semaphore sem; /* account for fragment usage */
++ wait_queue_head_t frag_wq; /* for poll(), etc. */
++ wait_queue_head_t stop_wq; /* for users of DCSR_STOPIRQEN */
++ u_long dcmd; /* DMA descriptor dcmd field */
++ volatile u32 *drcmr; /* the DMA request channel to use */
++ u_long dev_addr; /* device physical address for DMA */
++ int mapped:1; /* mmap()'ed buffers */
++ int output:1; /* 0 for input, 1 for output */
++} audio_stream_t;
++
++typedef struct {
++ audio_stream_t *output_stream;
++ audio_stream_t *input_stream;
++ int dev_dsp; /* audio device handle */
++ int rd_ref:1; /* open reference for recording */
++ int wr_ref:1; /* open reference for playback */
++ int (*client_ioctl)(struct inode *, struct file *, uint, ulong);
++ struct semaphore sem; /* prevent races in attach/release */
++} audio_state_t;
++
++extern int pxa_audio_attach(struct inode *inode, struct file *file,
++ audio_state_t *state);
++extern void pxa_audio_clear_buf(audio_stream_t *s);
++
+--- linux-2.4.27/drivers/sound/sa1100-audio.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/sound/sa1100-audio.c
+@@ -148,7 +148,8 @@
+ do {
+ dmabuf = consistent_alloc(GFP_KERNEL|GFP_DMA,
+ dmasize,
+- &dmaphys);
++ &dmaphys,
++ 0);
+ if (!dmabuf)
+ dmasize -= s->fragsize;
+ } while (!dmabuf && dmasize);
+--- linux-2.4.27/drivers/video/Config.in~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/video/Config.in
+@@ -50,6 +50,15 @@
+ if [ "$CONFIG_FB_SA1100" = "y" -a "$CONFIG_SA1100_CERF_CPLD" = "y" ]; then
+ bool 'Cerfboard Backlight (CerfPDA)' CONFIG_SA1100_CERF_LCD_BACKLIGHT
+ fi
++ tristate ' PXA LCD support' CONFIG_FB_PXA $CONFIG_ARCH_PXA
++ if [ "$CONFIG_FB_PXA" != "n" ]; then
++ choice 'LCD Bit Depth' \
++ "8-Bpp CONFIG_FB_PXA_8BPP \
++ 16-Bpp CONFIG_FB_PXA_16BPP" Bit-Depth
++ fi
++ if [ "$CONFIG_FB_PXA" != "n" -a "$CONFIG_ARCH_LUBBOCK" = "y" ]; then
++ bool ' Lubbock QVGA LCD support instead of DSTN' CONFIG_FB_PXA_QVGA
++ fi
+ fi
+ dep_tristate ' CyberPro 2000/2010/5000 support' CONFIG_FB_CYBER2000 $CONFIG_PCI
+ if [ "$CONFIG_APOLLO" = "y" ]; then
+@@ -295,7 +304,7 @@
+ if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
+ "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+ "$CONFIG_FB_TX3912" = "y" -o "$CONFIG_FB_CLPS711X" = "y" -o \
+- "$CONFIG_FB_DBMX1" = "y" ]; then
++ "$CONFIG_FB_DBMX1" = "y" -o "$CONFIG_FB_PXA" = "y" ]; then
+ define_tristate CONFIG_FBCON_CFB2 y
+ define_tristate CONFIG_FBCON_CFB4 y
+ else
+@@ -329,7 +338,7 @@
+ "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \
+ "$CONFIG_FB_STI" = "y" -o "$CONFIG_FB_HP300" = "y" -o \
+ "$CONFIG_FB_INTEL" = "y" -o \
+- "$CONFIG_FB_DBMX1" = "y" ]; then
++ "$CONFIG_FB_DBMX1" = "y" -o "$CONFIG_FB_PXA" = "y" ]; then
+ define_tristate CONFIG_FBCON_CFB8 y
+ else
+ if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
+@@ -372,7 +381,7 @@
+ "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
+ "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
+ "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_INTEL" = "y" -o \
+- "$CONFIG_FB_ANAKIN" = "y" -o \
++ "$CONFIG_FB_ANAKIN" = "y" -o "$CONFIG_FB_PXA" = "y" -o \
+ "$CONFIG_FB_DBMX1" = "y" ]; then
+ define_tristate CONFIG_FBCON_CFB16 y
+ else
+--- linux-2.4.27/drivers/video/Makefile~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/video/Makefile
+@@ -14,7 +14,7 @@
+ fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \
+ fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
+ fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
+- fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \
++ fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o pxafb.o \
+ cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o
+
+ # Each configuration option enables a list of files.
+@@ -129,6 +129,10 @@
+ obj-$(CONFIG_FB_BWTWO) += bwtwofb.o
+ obj-$(CONFIG_FB_HGA) += hgafb.o
+ obj-$(CONFIG_FB_SA1100) += sa1100fb.o
++obj-$(CONFIG_FB_PXA) += pxafb.o
++ifeq ($(CONFIG_PXA_CERF_PDA),y)
++ obj-$(CONFIG_FB_PXA) += lcdctrl.o lcdctrl_cerf.o
++endif
+ obj-$(CONFIG_FB_DBMX1) += dbmx1fb.o
+ obj-$(CONFIG_FB_VIRTUAL) += vfb.o
+ obj-$(CONFIG_FB_HIT) += hitfb.o fbgen.o
+--- linux-2.4.27/drivers/video/fbmem.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/video/fbmem.c
+@@ -109,6 +109,7 @@
+ extern int chips_init(void);
+ extern int g364fb_init(void);
+ extern int sa1100fb_init(void);
++extern int pxafb_init(void);
+ extern int fm2fb_init(void);
+ extern int fm2fb_setup(char*);
+ extern int q40fb_init(void);
+@@ -305,6 +306,9 @@
+ #ifdef CONFIG_FB_SA1100
+ { "sa1100", sa1100fb_init, NULL },
+ #endif
++#ifdef CONFIG_FB_PXA
++ { "pxa", pxafb_init, NULL },
++#endif
+ #ifdef CONFIG_FB_SUN3
+ { "sun3", sun3fb_init, sun3fb_setup },
+ #endif
+@@ -677,13 +681,13 @@
+ #elif defined(__i386__) || defined(__x86_64__)
+ if (boot_cpu_data.x86 > 3)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+-#elif defined(__arm__) || defined(__mips__)
++#elif defined(__mips__)
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ #elif defined(__sh__)
+ pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
+ #elif defined(__hppa__)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+-#elif defined(__ia64__)
++#elif defined(__ia64__) || defined(__arm__)
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ #elif defined(__hppa__)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+--- /dev/null
++++ linux-2.4.27/drivers/video/lcdctrl.c
+@@ -0,0 +1,223 @@
++/*
++ * lcdctrl.c
++ *
++ * Generic LCD control for brightness, contrast, etc.
++ * Device specific drivers implement a lcdctrl_device and
++ * provides access to it via lcdctrl_device_get_ops().
++ *
++ * Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * History:
++ * Mar 2002: Initial version [FB]
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++
++#include <video/lcdctrl.h>
++
++/*
++ * Set this to zero to remove all the debug statements via
++ * dead code elimination.
++ */
++#define DEBUGGING 0
++
++#if DEBUGGING
++static unsigned int lcd_debug = DEBUGGING;
++#else
++#define lcd_debug 0
++#endif
++
++/* -- prototypes -- */
++
++static int lcdctrl_ioctl(struct inode * inode, struct file *filp,
++ unsigned int cmd , unsigned long arg);
++static int lcdctrl_open(struct inode *inode, struct file *filp);
++static int lcdctrl_close(struct inode *inode, struct file *filp);
++
++/* -- variables -- */
++
++struct lcdctrl_device *lcd_device;
++
++static int intensity;
++static int brightness;
++static int contrast;
++
++static int enabled;
++static int sync_needed;
++static int chrdev_major;
++
++static struct file_operations lcdctrl_fops = {
++ ioctl: lcdctrl_ioctl,
++ open: lcdctrl_open,
++ release: lcdctrl_close
++};
++
++/* -- ioctl -- */
++
++static int lcdctrl_ioctl(struct inode * inode, struct file *filp,
++ unsigned int cmd , unsigned long arg)
++{
++ int ret;
++ ret = -EINVAL;
++
++ if( lcd_debug)
++ printk(KERN_INFO "lcdctrl_ioctl: cmd=%d, arg=%ld\n", cmd, arg);
++
++ switch(cmd)
++ {
++ case _LCDCTRL_IOCTL_ON:
++ ret = lcdctrl_enable();
++ break;
++ case _LCDCTRL_IOCTL_OFF:
++ ret = lcdctrl_disable();
++ break;
++ case _LCDCTRL_IOCTL_INTENSITY:
++ if ((arg >=0) && (arg <= 100))
++ ret = lcdctrl_set_intensity(arg);
++ break;
++ case _LCDCTRL_IOCTL_BRIGHTNESS:
++ if ((arg >=0) && (arg <= 100))
++ ret = lcdctrl_set_brightness(arg);
++ break;
++ case _LCDCTRL_IOCTL_CONTRAST:
++ if ((arg >=0) && (arg <= 100))
++ ret = lcdctrl_set_contrast(arg, LCD_NO_SYNC);
++ break;
++ case _LCDCTRL_IOCTL_GET_BRIGHTNESS:
++ ret = brightness;
++ break;
++ case _LCDCTRL_IOCTL_GET_CONTRAST:
++ ret = contrast;
++ break;
++ case _LCDCTRL_IOCTL_GET_INTENSITY:
++ ret = intensity;
++ break;
++
++ default:
++ printk(KERN_ERR "lcdctrl_ioctl: invalid ioctl\n");
++ break;
++ }
++
++ return ret;
++}
++
++static int lcdctrl_open(struct inode *inode, struct file *filp)
++{
++// MOD_INC_USE_COUNT;
++ return 0;
++}
++
++static int lcdctrl_close(struct inode *inode, struct file *filp)
++{
++// MOD_DEC_USE_COUNT;
++ return 0;
++}
++
++/* -- -- */
++
++int lcdctrl_enable( void)
++{
++ int result;
++
++ if( enabled) return 0;
++
++ result = lcd_device->enable();
++
++ lcdctrl_set_intensity( intensity);
++ lcdctrl_set_brightness( brightness);
++ lcdctrl_set_contrast( contrast, sync_needed);
++ sync_needed = LCD_NO_SYNC;
++
++ enabled = 1;
++ return result;
++}
++
++int lcdctrl_disable( void)
++{
++ enabled = 0;
++ return lcd_device->disable();
++}
++
++int lcdctrl_set_intensity( int i)
++{
++ intensity = i;
++ return lcd_device->set_intensity( i);
++}
++
++int lcdctrl_set_brightness( int b)
++{
++ brightness = b;
++ return lcd_device->set_brightness( b);
++}
++
++int lcdctrl_set_contrast( int c, int sync)
++{
++ contrast = c;
++ return lcd_device->set_contrast( c, sync);
++}
++
++int lcdctrl_get_intensity( void)
++{
++ return intensity;
++}
++
++int lcdctrl_get_brightness( void)
++{
++ return brightness;
++}
++
++int lcdctrl_get_contrast( void)
++{
++ return contrast;
++}
++
++/* -- -- */
++
++/* the device specific driver should implement this */
++struct lcdctrl_device *lcdctrl_device_get_ops(void);
++
++int lcdctrl_init( void)
++{
++ int ret;
++
++ lcd_device = lcdctrl_device_get_ops();
++
++ if( !lcd_device)
++ {
++ printk(KERN_ERR "lcdctrl_init: No lcd_device registered.\n");
++ return -EINVAL;
++ }
++
++ ret = lcd_device->init( &intensity, &brightness, &contrast);
++
++ sync_needed = LCD_SYNC_NEEDED;
++
++ if( ret == 0)
++ {
++ chrdev_major =
++ register_chrdev( 0,_LCD_CONTROL_NAME,&lcdctrl_fops);
++ if( lcd_debug)
++ printk(KERN_INFO "lcdctrl_init: OK\n");
++ }
++ return ret;
++}
+--- /dev/null
++++ linux-2.4.27/drivers/video/lcdctrl_cerf.c
+@@ -0,0 +1,175 @@
++/*
++ * lcdctrl_cerf.c
++ *
++ * Cerf LCD control for brightness and contrast.
++ *
++ * Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * History:
++ * Mar 2002: Initial version [FB]
++ *
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/arch/cerf_ucb1400gpio.h>
++
++#include <video/lcdctrl.h>
++
++/*
++ * Set this to zero to remove all the debug statements via
++ * dead code elimination.
++ */
++#define DEBUGGING 0
++
++#if DEBUGGING
++static unsigned int lcd_debug = DEBUGGING;
++#else
++#define lcd_debug 0
++#endif
++
++#define LCD_MAX_INTENSITY 0
++#define LCD_MAX_BRIGHTNESS 15
++#define LCD_MAX_CONTRAST 100
++
++#define LCD_DEFAULT_INTENSITY 0
++#define LCD_DEFAULT_BRIGHTNESS 14*100/(LCD_MAX_BRIGHTNESS)
++#define LCD_DEFAULT_CONTRAST 90*100/(LCD_MAX_CONTRAST)
++
++#define UP 1
++#define DOWN 0
++
++/* -- prototypes -- */
++
++static int cerf_lcdctrl_init( int *intensity, int *brightness, int *contrast);
++static int cerf_lcdctrl_enable(void);
++static int cerf_lcdctrl_disable(void);
++static int cerf_lcdctrl_set_intensity( int i);
++static int cerf_lcdctrl_set_brightness( int b);
++static int cerf_lcdctrl_set_contrast( int c, int sync);
++
++static void cerf_lcdctrl_contrast_step( int direction);
++
++/* -- variables -- */
++
++static int dev_contrast;
++
++/* -- -- */
++
++static struct lcdctrl_device cerf_dev = {
++ init: cerf_lcdctrl_init,
++ enable: cerf_lcdctrl_enable,
++ disable: cerf_lcdctrl_disable,
++ set_intensity: cerf_lcdctrl_set_intensity,
++ set_brightness: cerf_lcdctrl_set_brightness,
++ set_contrast: cerf_lcdctrl_set_contrast
++};
++
++static int cerf_lcdctrl_enable( void)
++{
++ cerf_ucb1400gpio_lcd_enable();
++
++ return 0;
++}
++
++static int cerf_lcdctrl_disable( void)
++{
++ cerf_ucb1400gpio_lcd_disable();
++
++ return 0;
++}
++
++static int cerf_lcdctrl_set_intensity( int i)
++{
++ int dev_intensity = LCD_MAX_INTENSITY*i/100;
++ if( lcd_debug)
++ printk(KERN_INFO "cerf_lcdctrl_set_intensity: "
++ "dev_intensity = %d\n", dev_intensity);
++ return 0;
++}
++
++static int cerf_lcdctrl_set_brightness( int b)
++{
++ int dev_brightness = LCD_MAX_BRIGHTNESS*b/100;
++ outw( dev_brightness, CERF_PDA_CPLD+CERF_PDA_CPLD_BRIGHTNESS);
++ if( lcd_debug)
++ printk(KERN_INFO "cerf_lcdctrl_set_brightness: "
++ "dev_brightness = %d\n", dev_brightness);
++ return 0;
++}
++
++static int cerf_lcdctrl_set_contrast( int c, int sync)
++{
++ int new_dev_contrast = LCD_MAX_CONTRAST*c/100;
++ int i;
++ int count;
++ int direction = UP;
++ if( sync == LCD_SYNC_NEEDED)
++ {
++ /* In order to sync we step down to the lowest contrast level */
++ for( i=0; i<LCD_MAX_CONTRAST; i++)
++ cerf_lcdctrl_contrast_step(DOWN);
++ dev_contrast = 0;
++ }
++
++ count = new_dev_contrast - dev_contrast;
++ if( count < 0)
++ {
++ /* new contrast is lower then current setting */
++ direction = DOWN;
++ count = -count;
++ }
++
++ for( i=0; i<count; i++)
++ cerf_lcdctrl_contrast_step(direction);
++
++ if( lcd_debug)
++ printk(KERN_INFO "cerf_lcdctrl_set_contrast: "
++ "dev_contrast = %d\n", new_dev_contrast);
++ dev_contrast = new_dev_contrast;
++
++ return 0;
++}
++
++/* -- -- */
++
++static void cerf_lcdctrl_contrast_step( int direction)
++{
++ cerf_ucb1400gpio_lcd_contrast_step( direction);
++}
++
++/* -- -- */
++
++static int cerf_lcdctrl_init( int *intensity, int *brightness, int *contrast)
++{
++ *intensity = LCD_DEFAULT_INTENSITY;
++ *brightness = LCD_DEFAULT_BRIGHTNESS;
++ *contrast = LCD_DEFAULT_CONTRAST;
++
++ if( lcd_debug)
++ printk(KERN_INFO "cerf_lcdctrl_init: OK\n");
++ return 0;
++}
++
++/* this is the hook for lcdctrl to access to the device specifics */
++struct lcdctrl_device *lcdctrl_device_get_ops(void)
++{
++ return &cerf_dev;
++}
+--- /dev/null
++++ linux-2.4.27/drivers/video/pxafb.c
+@@ -0,0 +1,1410 @@
++/*
++ * linux/drivers/video/pxafb.c
++ *
++ * Copyright (C) 1999 Eric A. Thomas
++ * Based on acornfb.c Copyright (C) Russell King.
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive for
++ * more details.
++ *
++ * Intel PXA250/210 LCD Controller Frame Buffer Driver
++ *
++ * Please direct your questions and comments on this driver to the following
++ * email address:
++ *
++ * linux-arm-kernel@lists.arm.linux.org.uk
++ *
++ *
++ * Code Status:
++ *
++ * 2001/08/03: <cbrake@accelent.com>
++ * - Ported from SA1100 to PXA250
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/fb.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/init.h>
++#include <linux/notifier.h>
++#include <linux/cpufreq.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/uaccess.h>
++
++#include <video/fbcon.h>
++#include <video/fbcon-mfb.h>
++#include <video/fbcon-cfb4.h>
++#include <video/fbcon-cfb8.h>
++#include <video/fbcon-cfb16.h>
++#include <video/lcdctrl.h> /* brightness, contrast, etc. control */
++
++/*
++ * debugging?
++ */
++#define DEBUG 0
++/*
++ * Complain if VAR is out of range.
++ */
++#define DEBUG_VAR 1
++
++#undef ASSABET_PAL_VIDEO
++
++#include "pxafb.h"
++
++void (*pxafb_blank_helper)(int blank);
++EXPORT_SYMBOL(pxafb_blank_helper);
++
++/*
++ * IMHO this looks wrong. In 8BPP, length should be 8.
++ */
++static struct pxafb_rgb rgb_8 = {
++ red: { offset: 0, length: 4, },
++ green: { offset: 0, length: 4, },
++ blue: { offset: 0, length: 4, },
++ transp: { offset: 0, length: 0, },
++};
++
++static struct pxafb_rgb def_rgb_16 = {
++ red: { offset: 11, length: 5, },
++ green: { offset: 5, length: 6, },
++ blue: { offset: 0, length: 5, },
++ transp: { offset: 0, length: 0, },
++};
++
++static struct pxafb_mach_info pxa_fb_info __initdata = {
++ pixclock: LCD_PIXCLOCK, /* clock period in ps */
++ bpp: LCD_BPP,
++ xres: LCD_XRES,
++ yres: LCD_YRES,
++ hsync_len: LCD_HORIZONTAL_SYNC_PULSE_WIDTH,
++ vsync_len: LCD_VERTICAL_SYNC_PULSE_WIDTH,
++ left_margin: LCD_BEGIN_OF_LINE_WAIT_COUNT,
++ upper_margin: LCD_BEGIN_FRAME_WAIT_COUNT,
++ right_margin: LCD_END_OF_LINE_WAIT_COUNT,
++ lower_margin: LCD_END_OF_FRAME_WAIT_COUNT,
++ sync: LCD_SYNC,
++ lccr0: LCD_LCCR0,
++ lccr3: LCD_LCCR3
++};
++
++static struct pxafb_mach_info * __init
++pxafb_get_machine_info(struct pxafb_info *fbi)
++{
++ return &pxa_fb_info;
++}
++
++static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
++static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
++
++static inline void pxafb_schedule_task(struct pxafb_info *fbi, u_int state)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++ /*
++ * We need to handle two requests being made at the same time.
++ * There are two important cases:
++ * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
++ * We must perform the unblanking, which will do our REENABLE for us.
++ * 2. When we are blanking, but immediately unblank before we have
++ * blanked. We do the "REENABLE" thing here as well, just to be sure.
++ */
++ if (fbi->task_state == C_ENABLE && state == C_REENABLE)
++ state = (u_int) -1;
++ if (fbi->task_state == C_DISABLE && state == C_ENABLE)
++ state = C_REENABLE;
++
++ if (state != (u_int)-1) {
++ fbi->task_state = state;
++ schedule_task(&fbi->task);
++ }
++ local_irq_restore(flags);
++}
++
++/*
++ * Get the VAR structure pointer for the specified console
++ */
++static inline struct fb_var_screeninfo *get_con_var(struct fb_info *info, int con)
++{
++ struct pxafb_info *fbi = (struct pxafb_info *)info;
++ return (con == fbi->currcon || con == -1) ? &fbi->fb.var : &fb_display[con].var;
++}
++
++/*
++ * Get the DISPLAY structure pointer for the specified console
++ */
++static inline struct display *get_con_display(struct fb_info *info, int con)
++{
++ struct pxafb_info *fbi = (struct pxafb_info *)info;
++ return (con < 0) ? fbi->fb.disp : &fb_display[con];
++}
++
++/*
++ * Get the CMAP pointer for the specified console
++ */
++static inline struct fb_cmap *get_con_cmap(struct fb_info *info, int con)
++{
++ struct pxafb_info *fbi = (struct pxafb_info *)info;
++ return (con == fbi->currcon || con == -1) ? &fbi->fb.cmap : &fb_display[con].cmap;
++}
++
++static inline u_int
++chan_to_field(u_int chan, struct fb_bitfield *bf)
++{
++ chan &= 0xffff;
++ chan >>= 16 - bf->length;
++ return chan << bf->offset;
++}
++
++static int
++pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
++ u_int trans, struct fb_info *info)
++{
++ struct pxafb_info *fbi = (struct pxafb_info *)info;
++ u_int val, ret = 1;
++
++ if (regno < fbi->palette_size) {
++ val = ((red >> 0) & 0xf800);
++ val |= ((green >> 5) & 0x07e0);
++ val |= ((blue >> 11) & 0x001f);
++
++ fbi->palette_cpu[regno] = val;
++ ret = 0;
++ }
++ return ret;
++}
++
++static int
++pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++ u_int trans, struct fb_info *info)
++{
++ struct pxafb_info *fbi = (struct pxafb_info *)info;
++ u_int val;
++ int ret = 1;
++
++ /*
++ * If greyscale is true, then we convert the RGB value
++ * to greyscale no mater what visual we are using.
++ */
++ if (fbi->fb.var.grayscale)
++ red = green = blue = (19595 * red + 38470 * green +
++ 7471 * blue) >> 16;
++
++ switch (fbi->fb.disp->visual) {
++ case FB_VISUAL_TRUECOLOR:
++ case FB_VISUAL_DIRECTCOLOR:
++ /*
++ * 12 or 16-bit True Colour. We encode the RGB value
++ * according to the RGB bitfield information.
++ */
++ if (regno <= 16) {
++ u16 *pal = fbi->fb.pseudo_palette;
++
++ val = chan_to_field(red, &fbi->fb.var.red);
++ val |= chan_to_field(green, &fbi->fb.var.green);
++ val |= chan_to_field(blue, &fbi->fb.var.blue);
++
++ pal[regno] = val;
++ ret = 0;
++ }
++ break;
++
++ case FB_VISUAL_PSEUDOCOLOR:
++ ret = pxafb_setpalettereg(regno, red, green, blue, trans, info);
++ break;
++ }
++
++ return ret;
++}
++
++/*
++ * pxafb_decode_var():
++ * Get the video params out of 'var'. If a value doesn't fit, round it up,
++ * if it's too big, return -EINVAL.
++ *
++ * Suggestion: Round up in the following order: bits_per_pixel, xres,
++ * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
++ * bitfields, horizontal timing, vertical timing.
++ */
++static int pxafb_validate_var(struct fb_var_screeninfo *var,
++ struct pxafb_info *fbi)
++{
++ int ret = -EINVAL;
++
++ if (var->xres < MIN_XRES)
++ var->xres = MIN_XRES;
++ if (var->yres < MIN_YRES)
++ var->yres = MIN_YRES;
++ if (var->xres > fbi->max_xres)
++ var->xres = fbi->max_xres;
++ if (var->yres > fbi->max_yres)
++ var->yres = fbi->max_yres;
++ var->xres_virtual =
++ var->xres_virtual < var->xres ? var->xres : var->xres_virtual;
++ var->yres_virtual =
++ var->yres_virtual < var->yres ? var->yres : var->yres_virtual;
++
++ DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
++ switch (var->bits_per_pixel) {
++#ifdef FBCON_HAS_CFB4
++ case 4: ret = 0; break;
++#endif
++#ifdef FBCON_HAS_CFB8
++ case 8: ret = 0; break;
++#endif
++#ifdef FBCON_HAS_CFB16
++ case 12:
++ /* make sure we are in passive mode */
++ if (!(fbi->lccr0 & LCCR0_PAS))
++ ret = 0;
++ break;
++
++ case 16:
++ /*
++ * 16 bits works apparemtly fine in passive mode for those,
++ * so don't complain
++ */
++ if (machine_is_lubbock() ||
++ machine_is_pxa_cerf()) {
++ ret = 0;
++ } else
++ /* make sure we are in active mode */
++ if ((fbi->lccr0 & LCCR0_PAS))
++ ret = 0;
++ break;
++#endif
++ default:
++ break;
++ }
++
++ return ret;
++}
++
++static inline void pxafb_set_truecolor(u_int is_true_color)
++{
++ DPRINTK("true_color = %d\n", is_true_color);
++}
++
++static void
++pxafb_hw_set_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi)
++{
++
++ fb_set_cmap(&fbi->fb.cmap, 1, pxafb_setcolreg, &fbi->fb);
++
++ /* Set board control register to handle new color depth */
++ pxafb_set_truecolor(var->bits_per_pixel >= 16);
++
++ pxafb_activate_var(var, fbi);
++
++}
++
++/*
++ * pxafb_set_var():
++ * Set the user defined part of the display for the specified console
++ */
++static int
++pxafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++{
++ struct pxafb_info *fbi = (struct pxafb_info *)info;
++ struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con);
++ struct display *display = get_con_display(&fbi->fb, con);
++ int err, chgvar = 0, rgbidx;
++
++ DPRINTK("set_var\n");
++
++ /*
++ * Decode var contents into a par structure, adjusting any
++ * out of range values.
++ */
++ err = pxafb_validate_var(var, fbi);
++ if (err)
++ return err;
++
++ if (var->activate & FB_ACTIVATE_TEST)
++ return 0;
++
++ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
++ return -EINVAL;
++
++ if (dvar->xres != var->xres)
++ chgvar = 1;
++ if (dvar->yres != var->yres)
++ chgvar = 1;
++ if (dvar->xres_virtual != var->xres_virtual)
++ chgvar = 1;
++ if (dvar->yres_virtual != var->yres_virtual)
++ chgvar = 1;
++ if (dvar->bits_per_pixel != var->bits_per_pixel)
++ chgvar = 1;
++ if (con < 0)
++ chgvar = 0;
++
++ switch (var->bits_per_pixel) {
++#ifdef FBCON_HAS_CFB4
++ case 4:
++ if (fbi->cmap_static)
++ display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
++ else
++ display->visual = FB_VISUAL_PSEUDOCOLOR;
++ display->line_length = var->xres / 2;
++ display->dispsw = &fbcon_cfb4;
++ rgbidx = RGB_8;
++ break;
++#endif
++#ifdef FBCON_HAS_CFB8
++ case 8:
++ if (fbi->cmap_static)
++ display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
++ else
++ display->visual = FB_VISUAL_PSEUDOCOLOR;
++ display->line_length = var->xres;
++ display->dispsw = &fbcon_cfb8;
++ rgbidx = RGB_8;
++ break;
++#endif
++#ifdef FBCON_HAS_CFB16
++ case 12:
++ case 16:
++ display->visual = FB_VISUAL_TRUECOLOR;
++ display->line_length = var->xres * 2;
++ display->dispsw = &fbcon_cfb16;
++ display->dispsw_data = fbi->fb.pseudo_palette;
++ rgbidx = RGB_16;
++ break;
++#endif
++ default:
++ rgbidx = 0;
++ display->dispsw = &fbcon_dummy;
++ break;
++ }
++
++ display->screen_base = fbi->screen_cpu;
++ display->next_line = display->line_length;
++ display->type = fbi->fb.fix.type;
++ display->type_aux = fbi->fb.fix.type_aux;
++ display->ypanstep = fbi->fb.fix.ypanstep;
++ display->ywrapstep = fbi->fb.fix.ywrapstep;
++ display->can_soft_blank = 1;
++ display->inverse = 0;
++
++ *dvar = *var;
++ dvar->activate &= ~FB_ACTIVATE_ALL;
++
++ /*
++ * Copy the RGB parameters for this display
++ * from the machine specific parameters.
++ */
++ dvar->red = fbi->rgb[rgbidx]->red;
++ dvar->green = fbi->rgb[rgbidx]->green;
++ dvar->blue = fbi->rgb[rgbidx]->blue;
++ dvar->transp = fbi->rgb[rgbidx]->transp;
++
++ DPRINTK("RGBT length = %d:%d:%d:%d\n",
++ dvar->red.length, dvar->green.length, dvar->blue.length,
++ dvar->transp.length);
++
++ DPRINTK("RGBT offset = %d:%d:%d:%d\n",
++ dvar->red.offset, dvar->green.offset, dvar->blue.offset,
++ dvar->transp.offset);
++
++ /*
++ * Update the old var. The fbcon drivers still use this.
++ * Once they are using fbi->fb.var, this can be dropped.
++ */
++ display->var = *dvar;
++
++ /*
++ * If we are setting all the virtual consoles, also set the
++ * defaults used to create new consoles.
++ */
++ if (var->activate & FB_ACTIVATE_ALL)
++ fbi->fb.disp->var = *dvar;
++
++ /*
++ * If the console has changed and the console has defined
++ * a changevar function, call that function.
++ */
++ if (chgvar && info && fbi->fb.changevar)
++ fbi->fb.changevar(con);
++
++ /* If the current console is selected, activate the new var. */
++ if (con != fbi->currcon)
++ return 0;
++
++ pxafb_hw_set_var(dvar, fbi);
++
++ return 0;
++}
++
++static int
++__do_set_cmap(struct fb_cmap *cmap, int kspc, int con,
++ struct fb_info *info)
++{
++ struct pxafb_info *fbi = (struct pxafb_info *)info;
++ struct fb_cmap *dcmap = get_con_cmap(info, con);
++ int err = 0;
++
++ if (con == -1)
++ con = fbi->currcon;
++
++ /* no colormap allocated? (we always have "this" colour map allocated) */
++ if (con >= 0)
++ err = fb_alloc_cmap(&fb_display[con].cmap, fbi->palette_size, 0);
++
++ if (!err && con == fbi->currcon)
++ err = fb_set_cmap(cmap, kspc, pxafb_setcolreg, info);
++
++ if (!err)
++ fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
++
++ return err;
++}
++
++static int
++pxafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
++ struct fb_info *info)
++{
++ struct display *disp = get_con_display(info, con);
++
++ if (disp->visual == FB_VISUAL_TRUECOLOR)
++ return -EINVAL;
++
++ return __do_set_cmap(cmap, kspc, con, info);
++}
++
++static int
++pxafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
++{
++ struct display *display = get_con_display(info, con);
++
++ *fix = info->fix;
++
++ fix->line_length = display->line_length;
++ fix->visual = display->visual;
++ return 0;
++}
++
++static int
++pxafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++{
++ *var = *get_con_var(info, con);
++ return 0;
++}
++
++static int
++pxafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
++{
++ struct fb_cmap *dcmap = get_con_cmap(info, con);
++ fb_copy_cmap(dcmap, cmap, kspc ? 0 : 2);
++ return 0;
++}
++
++static struct fb_ops pxafb_ops = {
++ owner: THIS_MODULE,
++ fb_get_fix: pxafb_get_fix,
++ fb_get_var: pxafb_get_var,
++ fb_set_var: pxafb_set_var,
++ fb_get_cmap: pxafb_get_cmap,
++ fb_set_cmap: pxafb_set_cmap,
++};
++
++/*
++ * pxafb_switch():
++ * Change to the specified console. Palette and video mode
++ * are changed to the console's stored parameters.
++ *
++ * Uh oh, this can be called from a tasklet (IRQ)
++ */
++static int pxafb_switch(int con, struct fb_info *info)
++{
++ struct pxafb_info *fbi = (struct pxafb_info *)info;
++ struct display *disp;
++ struct fb_cmap *cmap;
++
++ DPRINTK("con=%d info->modename=%s\n", con, fbi->fb.modename);
++
++ if (con == fbi->currcon)
++ return 0;
++
++ if (fbi->currcon >= 0) {
++ disp = fb_display + fbi->currcon;
++
++ /*
++ * Save the old colormap and video mode.
++ */
++ disp->var = fbi->fb.var;
++
++ if (disp->cmap.len)
++ fb_copy_cmap(&fbi->fb.cmap, &disp->cmap, 0);
++ }
++
++ fbi->currcon = con;
++ disp = fb_display + con;
++
++ /*
++ * Make sure that our colourmap contains 256 entries.
++ */
++ fb_alloc_cmap(&fbi->fb.cmap, 256, 0);
++
++ if (disp->cmap.len)
++ cmap = &disp->cmap;
++ else
++ cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
++
++ fb_copy_cmap(cmap, &fbi->fb.cmap, 0);
++
++ fbi->fb.var = disp->var;
++ fbi->fb.var.activate = FB_ACTIVATE_NOW;
++
++ pxafb_set_var(&fbi->fb.var, con, info);
++ return 0;
++}
++
++/*
++ * Formal definition of the VESA spec:
++ * On
++ * This refers to the state of the display when it is in full operation
++ * Stand-By
++ * This defines an optional operating state of minimal power reduction with
++ * the shortest recovery time
++ * Suspend
++ * This refers to a level of power management in which substantial power
++ * reduction is achieved by the display. The display can have a longer
++ * recovery time from this state than from the Stand-by state
++ * Off
++ * This indicates that the display is consuming the lowest level of power
++ * and is non-operational. Recovery from this state may optionally require
++ * the user to manually power on the monitor
++ *
++ * Now, the fbdev driver adds an additional state, (blank), where they
++ * turn off the video (maybe by colormap tricks), but don't mess with the
++ * video itself: think of it semantically between on and Stand-By.
++ *
++ * So here's what we should do in our fbdev blank routine:
++ *
++ * VESA_NO_BLANKING (mode 0) Video on, front/back light on
++ * VESA_VSYNC_SUSPEND (mode 1) Video on, front/back light off
++ * VESA_HSYNC_SUSPEND (mode 2) Video on, front/back light off
++ * VESA_POWERDOWN (mode 3) Video off, front/back light off
++ *
++ * This will match the matrox implementation.
++ */
++/*
++ * pxafb_blank():
++ * Blank the display by setting all palette values to zero. Note, the
++ * 12 and 16 bpp modes don't really use the palette, so this will not
++ * blank the display in all modes.
++ */
++static void pxafb_blank(int blank, struct fb_info *info)
++{
++ struct pxafb_info *fbi = (struct pxafb_info *)info;
++ int i;
++
++ DPRINTK("pxafb_blank: blank=%d info->modename=%s\n", blank,
++ fbi->fb.modename);
++
++ switch (blank) {
++ case VESA_POWERDOWN:
++ case VESA_VSYNC_SUSPEND:
++ case VESA_HSYNC_SUSPEND:
++ if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
++ fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
++ for (i = 0; i < fbi->palette_size; i++)
++ pxafb_setpalettereg(i, 0, 0, 0, 0, info);
++ pxafb_schedule_task(fbi, C_DISABLE);
++ if (pxafb_blank_helper)
++ pxafb_blank_helper(blank);
++ break;
++
++ case VESA_NO_BLANKING:
++ if (pxafb_blank_helper)
++ pxafb_blank_helper(blank);
++ if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
++ fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
++ fb_set_cmap(&fbi->fb.cmap, 1, pxafb_setcolreg, info);
++ pxafb_schedule_task(fbi, C_ENABLE);
++ }
++}
++
++static int pxafb_updatevar(int con, struct fb_info *info)
++{
++ DPRINTK("entered\n");
++ return 0;
++}
++
++/*
++ * Calculate the PCD value from the clock rate (in picoseconds).
++ * We take account of the PPCR clock setting.
++ */
++static inline int get_pcd(unsigned int pixclock)
++{
++ unsigned int pcd;
++
++ if (pixclock) {
++ pcd = get_lclk_frequency_10khz() * pixclock;
++ pcd /= 100000000;
++ pcd += 1; /* make up for integer math truncations */
++ } else {
++ printk(KERN_WARNING "Please convert me to use the PCD calculations\n");
++ pcd = 0;
++ }
++ return pcd;
++}
++
++/*
++ * pxafb_activate_var():
++ * Configures LCD Controller based on entries in var parameter. Settings are
++ * only written to the controller if changes were made.
++ */
++static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi)
++{
++ struct pxafb_lcd_reg new_regs;
++// u_int pcd = get_pcd(var->pixclock);
++ u_long flags;
++
++ DPRINTK("Configuring PXA LCD\n");
++
++ DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
++ var->xres, var->hsync_len,
++ var->left_margin, var->right_margin);
++ DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
++ var->yres, var->vsync_len,
++ var->upper_margin, var->lower_margin);
++
++#if DEBUG_VAR
++ if (var->xres < 16 || var->xres > 1024)
++ printk(KERN_ERR "%s: invalid xres %d\n",
++ fbi->fb.fix.id, var->xres);
++ if (var->hsync_len < 1 || var->hsync_len > 64)
++ printk(KERN_ERR "%s: invalid hsync_len %d\n",
++ fbi->fb.fix.id, var->hsync_len);
++ if (var->left_margin < 1 || var->left_margin > 255)
++ printk(KERN_ERR "%s: invalid left_margin %d\n",
++ fbi->fb.fix.id, var->left_margin);
++ if (var->right_margin < 1 || var->right_margin > 255)
++ printk(KERN_ERR "%s: invalid right_margin %d\n",
++ fbi->fb.fix.id, var->right_margin);
++ if (var->yres < 1 || var->yres > 1024)
++ printk(KERN_ERR "%s: invalid yres %d\n",
++ fbi->fb.fix.id, var->yres);
++ if (var->vsync_len < 1 || var->vsync_len > 64)
++ printk(KERN_ERR "%s: invalid vsync_len %d\n",
++ fbi->fb.fix.id, var->vsync_len);
++ if (var->upper_margin < 0 || var->upper_margin > 255)
++ printk(KERN_ERR "%s: invalid upper_margin %d\n",
++ fbi->fb.fix.id, var->upper_margin);
++ if (var->lower_margin < 0 || var->lower_margin > 255)
++ printk(KERN_ERR "%s: invalid lower_margin %d\n",
++ fbi->fb.fix.id, var->lower_margin);
++#endif
++
++#if defined (CONFIG_PXA_CERF_PDA)
++ new_regs.lccr0 = fbi->lccr0;
++ new_regs.lccr1 =
++ LCCR1_DisWdth(var->xres) +
++ LCCR1_HorSnchWdth(var->hsync_len) +
++ LCCR1_BegLnDel(var->left_margin) +
++ LCCR1_EndLnDel(var->right_margin);
++
++ new_regs.lccr2 =
++ LCCR2_DisHght(var->yres) +
++ LCCR2_VrtSnchWdth(var->vsync_len) +
++ LCCR2_BegFrmDel(var->upper_margin) +
++ LCCR2_EndFrmDel(var->lower_margin);
++
++ new_regs.lccr3 = fbi->lccr3
++ |
++ (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
++ (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
++#elif defined (CONFIG_FB_PXA_QVGA)
++ new_regs.lccr0 = fbi->lccr0;
++ new_regs.lccr1 =
++ LCCR1_DisWdth(var->xres) +
++ LCCR1_HorSnchWdth(var->hsync_len) +
++ LCCR1_BegLnDel(var->left_margin) +
++ LCCR1_EndLnDel(var->right_margin);
++ new_regs.lccr2 =
++ LCCR2_DisHght(var->yres) +
++ LCCR2_VrtSnchWdth(var->vsync_len) +
++ LCCR2_BegFrmDel(var->upper_margin) +
++ LCCR2_EndFrmDel(var->lower_margin);
++ new_regs.lccr3 = fbi->lccr3;
++#else
++ // FIXME using hardcoded values for now
++ new_regs.lccr0 = fbi->lccr0;
++// |
++// LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
++// LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
++
++ new_regs.lccr1 = 0x3030A7F;
++// LCCR1_DisWdth(var->xres) +
++// LCCR1_HorSnchWdth(var->hsync_len) +
++// LCCR1_BegLnDel(var->left_margin) +
++// LCCR1_EndLnDel(var->right_margin);
++
++ new_regs.lccr2 = 0x4EF;
++// LCCR2_DisHght(var->yres) +
++// LCCR2_VrtSnchWdth(var->vsync_len) +
++// LCCR2_BegFrmDel(var->upper_margin) +
++// LCCR2_EndFrmDel(var->lower_margin);
++
++ new_regs.lccr3 = fbi->lccr3;
++// |
++// (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
++// (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) |
++// LCCR3_ACBsCntOff;
++#endif
++
++// if (pcd)
++// new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
++
++ DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
++ DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
++ DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2);
++ DPRINTK("nlccr3 = 0x%08x\n", new_regs.lccr3);
++
++ /* Update shadow copy atomically */
++ local_irq_save(flags);
++
++ /* setup dma descriptors */
++ fbi->dmadesc_fblow_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 3*16);
++ fbi->dmadesc_fbhigh_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 2*16);
++ fbi->dmadesc_palette_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 1*16);
++
++ fbi->dmadesc_fblow_dma = fbi->palette_dma - 3*16;
++ fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16;
++ fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16;
++
++ #define BYTES_PER_PANEL ((fbi->lccr0 & LCCR0_SDS) ? (var->xres * var->yres * var->bits_per_pixel / 8 / 2) : \
++ (var->xres * var->yres * var->bits_per_pixel / 8))
++
++ /* populate descriptors */
++ fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma;
++ fbi->dmadesc_fblow_cpu->fsadr = fbi->screen_dma + BYTES_PER_PANEL;
++ fbi->dmadesc_fblow_cpu->fidr = 0;
++ fbi->dmadesc_fblow_cpu->ldcmd = BYTES_PER_PANEL;
++
++ fbi->fdadr1 = fbi->dmadesc_fblow_dma; /* only used in dual-panel mode */
++
++ fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma;
++ fbi->dmadesc_fbhigh_cpu->fidr = 0;
++ fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL;
++
++ fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma;
++ fbi->dmadesc_palette_cpu->fidr = 0;
++ fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL;
++
++ if( var->bits_per_pixel < 12)
++ {
++ /* assume any mode with <12 bpp is palette driven */
++ fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
++ fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma;
++ fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */
++ }
++ else
++ {
++ /* palette shouldn't be loaded in true-color mode */
++ fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
++ fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
++ }
++
++ DPRINTK("fbi->dmadesc_fblow_cpu = 0x%x\n", fbi->dmadesc_fblow_cpu);
++ DPRINTK("fbi->dmadesc_fbhigh_cpu = 0x%x\n", fbi->dmadesc_fbhigh_cpu);
++ DPRINTK("fbi->dmadesc_palette_cpu = 0x%x\n", fbi->dmadesc_palette_cpu);
++ DPRINTK("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma);
++ DPRINTK("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma);
++ DPRINTK("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma);
++
++ DPRINTK("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr);
++ DPRINTK("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr);
++ DPRINTK("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr);
++
++ DPRINTK("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr);
++ DPRINTK("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr);
++ DPRINTK("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr);
++
++ DPRINTK("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd);
++ DPRINTK("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd);
++ DPRINTK("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd);
++
++ fbi->reg_lccr0 = new_regs.lccr0;
++ fbi->reg_lccr1 = new_regs.lccr1;
++ fbi->reg_lccr2 = new_regs.lccr2;
++ fbi->reg_lccr3 = new_regs.lccr3;
++ local_irq_restore(flags);
++
++ /*
++ * Only update the registers if the controller is enabled
++ * and something has changed.
++ */
++ if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) ||
++ (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) ||
++ (FDADR0 != fbi->fdadr0) || (FDADR1 != fbi->fdadr1))
++ pxafb_schedule_task(fbi, C_REENABLE);
++
++ return 0;
++}
++
++/*
++ * NOTE! The following functions are purely helpers for set_ctrlr_state.
++ * Do not call them directly; set_ctrlr_state does the correct serialisation
++ * to ensure that things happen in the right way 100% of time time.
++ * -- rmk
++ */
++
++/*
++ * FIXME: move LCD power stuff into pxafb_power_up_lcd()
++ * Also, I'm expecting that the backlight stuff should
++ * be handled differently.
++ */
++static void pxafb_backlight_on(struct pxafb_info *fbi)
++{
++ DPRINTK("backlight on\n");
++
++#ifdef CONFIG_ARCH_PXA_IDP
++ if(machine_is_pxa_idp()) {
++ FB_BACKLIGHT_ON();
++ }
++#endif
++}
++
++/*
++ * FIXME: move LCD power stuf into pxafb_power_down_lcd()
++ * Also, I'm expecting that the backlight stuff should
++ * be handled differently.
++ */
++static void pxafb_backlight_off(struct pxafb_info *fbi)
++{
++ DPRINTK("backlight off\n");
++
++#ifdef CONFIG_ARCH_PXA_IDP
++ if(machine_is_pxa_idp()) {
++ FB_BACKLIGHT_OFF();
++ }
++#endif
++
++}
++
++static void pxafb_power_up_lcd(struct pxafb_info *fbi)
++{
++ DPRINTK("LCD power on\n");
++ CKEN |= CKEN16_LCD;
++
++ if(machine_is_pxa_cerf()) {
++ lcdctrl_enable();
++ }
++
++#if CONFIG_ARCH_PXA_IDP
++ /* set GPIOs, etc */
++ if(machine_is_pxa_idp()) {
++ // FIXME need to add proper delays
++ FB_PWR_ON();
++ FB_VLCD_ON(); // FIXME this should be after scanning starts
++ }
++#endif
++}
++
++static void pxafb_power_down_lcd(struct pxafb_info *fbi)
++{
++ DPRINTK("LCD power off\n");
++ CKEN &= ~CKEN16_LCD;
++
++ if(machine_is_pxa_cerf()) {
++ lcdctrl_disable();
++ }
++
++ /* set GPIOs, etc */
++#if CONFIG_ARCH_PXA_IDP
++ if(machine_is_pxa_idp()) {
++ // FIXME need to add proper delays
++ FB_PWR_OFF();
++ FB_VLCD_OFF(); // FIXME this should be before scanning stops
++ }
++#endif
++
++}
++
++static void pxafb_setup_gpio(struct pxafb_info *fbi)
++{
++ unsigned int lccr0;
++
++ /*
++ * setup is based on type of panel supported
++ */
++
++ lccr0 = fbi->lccr0;
++
++ /* 4 bit interface */
++ if ((lccr0 & LCCR0_CMS) && (lccr0 & LCCR0_SDS) && !(lccr0 & LCCR0_DPD))
++ {
++ // bits 58-61
++ GPDR1 |= (0xf << 26);
++ GAFR1_U = (GAFR1_U & ~(0xff << 20)) | (0xaa << 20);
++
++ // bits 74-77
++ GPDR2 |= (0xf << 10);
++ GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
++ }
++
++ /* 8 bit interface */
++ else if (((lccr0 & LCCR0_CMS) && ((lccr0 & LCCR0_SDS) || (lccr0 & LCCR0_DPD))) ||
++ (!(lccr0 & LCCR0_CMS) && !(lccr0 & LCCR0_PAS) && !(lccr0 & LCCR0_SDS)))
++ {
++ // bits 58-65
++ GPDR1 |= (0x3f << 26);
++ GPDR2 |= (0x3);
++
++ GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
++ GAFR2_L = (GAFR2_L & ~0xf) | (0xa);
++
++ // bits 74-77
++ GPDR2 |= (0xf << 10);
++ GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
++ }
++
++ /* 16 bit interface */
++ else if (!(lccr0 & LCCR0_CMS) && ((lccr0 & LCCR0_SDS) || (lccr0 & LCCR0_PAS)))
++ {
++ // bits 58-77
++ GPDR1 |= (0x3f << 26);
++ GPDR2 |= 0x00003fff;
++
++ GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
++ GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
++ }
++ else
++ {
++ printk( KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
++ }
++}
++
++static void pxafb_enable_controller(struct pxafb_info *fbi)
++{
++ DPRINTK("Enabling LCD controller\n");
++
++ /* Sequence from 11.7.10 */
++ LCCR3 = fbi->reg_lccr3;
++ LCCR2 = fbi->reg_lccr2;
++ LCCR1 = fbi->reg_lccr1;
++ LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB;
++
++ /* FIXME we used to have LCD power control here */
++
++ FDADR0 = fbi->fdadr0;
++ FDADR1 = fbi->fdadr1;
++ LCCR0 |= LCCR0_ENB;
++
++ DPRINTK("FDADR0 = 0x%08x\n", (unsigned int)FDADR0);
++ DPRINTK("FDADR1 = 0x%08x\n", (unsigned int)FDADR1);
++ DPRINTK("LCCR0 = 0x%08x\n", (unsigned int)LCCR0);
++ DPRINTK("LCCR1 = 0x%08x\n", (unsigned int)LCCR1);
++ DPRINTK("LCCR2 = 0x%08x\n", (unsigned int)LCCR2);
++ DPRINTK("LCCR3 = 0x%08x\n", (unsigned int)LCCR3);
++}
++
++static void pxafb_disable_controller(struct pxafb_info *fbi)
++{
++ DECLARE_WAITQUEUE(wait, current);
++
++ DPRINTK("Disabling LCD controller\n");
++
++ /* FIXME add power down GPIO stuff here */
++
++ add_wait_queue(&fbi->ctrlr_wait, &wait);
++ set_current_state(TASK_UNINTERRUPTIBLE);
++
++ LCSR = 0xffffffff; /* Clear LCD Status Register */
++ LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */
++ LCCR0 &= ~LCCR0_ENB; /* Disable LCD Controller */
++
++ schedule_timeout(20 * HZ / 1000);
++ current->state = TASK_RUNNING;
++ remove_wait_queue(&fbi->ctrlr_wait, &wait);
++}
++
++/*
++ * pxafb_handle_irq: Handle 'LCD DONE' interrupts.
++ */
++static void pxafb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct pxafb_info *fbi = dev_id;
++ unsigned int lcsr = LCSR;
++
++ if (lcsr & LCSR_LDD) {
++ LCCR0 |= LCCR0_LDM;
++ wake_up(&fbi->ctrlr_wait);
++ }
++
++ LCSR = lcsr;
++}
++
++/*
++ * This function must be called from task context only, since it will
++ * sleep when disabling the LCD controller, or if we get two contending
++ * processes trying to alter state.
++ */
++static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
++{
++ u_int old_state;
++
++ down(&fbi->ctrlr_sem);
++
++ old_state = fbi->state;
++
++ switch (state) {
++ case C_DISABLE_CLKCHANGE:
++ /*
++ * Disable controller for clock change. If the
++ * controller is already disabled, then do nothing.
++ */
++ if (old_state != C_DISABLE) {
++ fbi->state = state;
++ pxafb_disable_controller(fbi);
++ }
++ break;
++
++ case C_DISABLE:
++ /*
++ * Disable controller
++ */
++ if (old_state != C_DISABLE) {
++ fbi->state = state;
++
++ pxafb_backlight_off(fbi);
++ if (old_state != C_DISABLE_CLKCHANGE)
++ pxafb_disable_controller(fbi);
++ pxafb_power_down_lcd(fbi);
++ }
++ break;
++
++ case C_ENABLE_CLKCHANGE:
++ /*
++ * Enable the controller after clock change. Only
++ * do this if we were disabled for the clock change.
++ */
++ if (old_state == C_DISABLE_CLKCHANGE) {
++ fbi->state = C_ENABLE;
++ pxafb_enable_controller(fbi);
++ }
++ break;
++
++ case C_REENABLE:
++ /*
++ * Re-enable the controller only if it was already
++ * enabled. This is so we reprogram the control
++ * registers.
++ */
++ if (old_state == C_ENABLE) {
++ pxafb_disable_controller(fbi);
++ pxafb_setup_gpio(fbi);
++ pxafb_enable_controller(fbi);
++ }
++ break;
++
++ case C_ENABLE:
++ /*
++ * Power up the LCD screen, enable controller, and
++ * turn on the backlight.
++ */
++ if (old_state != C_ENABLE) {
++ fbi->state = C_ENABLE;
++ pxafb_setup_gpio(fbi);
++ pxafb_power_up_lcd(fbi);
++ pxafb_enable_controller(fbi);
++ pxafb_backlight_on(fbi);
++ }
++ break;
++ }
++ up(&fbi->ctrlr_sem);
++}
++
++/*
++ * Our LCD controller task (which is called when we blank or unblank)
++ * via keventd.
++ */
++static void pxafb_task(void *dummy)
++{
++ struct pxafb_info *fbi = dummy;
++ u_int state = xchg(&fbi->task_state, -1);
++
++ set_ctrlr_state(fbi, state);
++}
++
++#ifdef CONFIG_CPU_FREQ
++/*
++ * CPU clock speed change handler. We need to adjust the LCD timing
++ * parameters when the CPU clock is adjusted by the power management
++ * subsystem.
++ */
++static int
++pxafb_clkchg_notifier(struct notifier_block *nb, unsigned long val,
++ void *data)
++{
++ struct pxafb_info *fbi = TO_INF(nb, clockchg);
++ u_int pcd;
++
++ switch (val) {
++ case CPUFREQ_MINMAX:
++ /* todo: fill in min/max values */
++ break;
++
++ case CPUFREQ_PRECHANGE:
++ set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
++ break;
++
++ case CPUFREQ_POSTCHANGE:
++ pcd = get_pcd(fbi->fb.var.pixclock);
++ fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
++ set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
++ break;
++ }
++ return 0;
++}
++#endif
++
++#ifdef CONFIG_PM
++/*
++ * Power management hook. Note that we won't be called from IRQ context,
++ * unlike the blank functions above, so we may sleep.
++ */
++static int
++pxafb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
++{
++ struct pxafb_info *fbi = pm_dev->data;
++
++ DPRINTK("pm_callback: %d\n", req);
++
++ if (req == PM_SUSPEND || req == PM_RESUME) {
++ int state = (int)data;
++
++ if (state == 0) {
++ /* Enter D0. */
++ set_ctrlr_state(fbi, C_ENABLE);
++ } else {
++ /* Enter D1-D3. Disable the LCD controller. */
++ set_ctrlr_state(fbi, C_DISABLE);
++ }
++ }
++ DPRINTK("done\n");
++ return 0;
++}
++#endif
++
++/*
++ * pxafb_map_video_memory():
++ * Allocates the DRAM memory for the frame buffer. This buffer is
++ * remapped into a non-cached, non-buffered, memory region to
++ * allow palette and pixel writes to occur without flushing the
++ * cache. Once this area is remapped, all virtual memory
++ * access to the video memory should occur at the new region.
++ */
++static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
++{
++ u_long palette_mem_size;
++
++ /*
++ * We reserve one page for the palette, plus the size
++ * of the framebuffer.
++ *
++ * layout of stuff in memory
++ *
++ * fblow descriptor
++ * fbhigh descriptor
++ * palette descriptor
++ * palette
++ * page boundary->
++ * frame buffer
++ */
++ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
++ fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
++ &fbi->map_dma, PTE_BUFFERABLE);
++
++ if (fbi->map_cpu) {
++ fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
++ fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
++ fbi->fb.fix.smem_start = fbi->screen_dma;
++
++ fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
++
++ palette_mem_size = fbi->palette_size * sizeof(u16);
++
++ DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
++
++ fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
++ fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
++
++ }
++
++ return fbi->map_cpu ? 0 : -ENOMEM;
++}
++
++/* Fake monspecs to fill in fbinfo structure */
++static struct fb_monspecs monspecs __initdata = {
++ 30000, 70000, 50, 65, 0 /* Generic */
++};
++
++
++static struct pxafb_info * __init pxafb_init_fbinfo(void)
++{
++ struct pxafb_mach_info *inf;
++ struct pxafb_info *fbi;
++
++ fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(struct display) +
++ sizeof(u16) * 16, GFP_KERNEL);
++ if (!fbi)
++ return NULL;
++
++ memset(fbi, 0, sizeof(struct pxafb_info) + sizeof(struct display));
++
++ fbi->currcon = -1;
++
++ strcpy(fbi->fb.fix.id, PXA_NAME);
++
++ fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
++ fbi->fb.fix.type_aux = 0;
++ fbi->fb.fix.xpanstep = 0;
++ fbi->fb.fix.ypanstep = 0;
++ fbi->fb.fix.ywrapstep = 0;
++ fbi->fb.fix.accel = FB_ACCEL_NONE;
++
++ fbi->fb.var.nonstd = 0;
++ fbi->fb.var.activate = FB_ACTIVATE_NOW;
++ fbi->fb.var.height = -1;
++ fbi->fb.var.width = -1;
++ fbi->fb.var.accel_flags = 0;
++ fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
++
++ strcpy(fbi->fb.modename, PXA_NAME);
++ strcpy(fbi->fb.fontname, "Acorn8x8");
++
++ fbi->fb.fbops = &pxafb_ops;
++ fbi->fb.changevar = NULL;
++ fbi->fb.switch_con = pxafb_switch;
++ fbi->fb.updatevar = pxafb_updatevar;
++ fbi->fb.blank = pxafb_blank;
++ fbi->fb.flags = FBINFO_FLAG_DEFAULT;
++ fbi->fb.node = -1;
++ fbi->fb.monspecs = monspecs;
++ fbi->fb.disp = (struct display *)(fbi + 1);
++ fbi->fb.pseudo_palette = (void *)(fbi->fb.disp + 1);
++
++ fbi->rgb[RGB_8] = &rgb_8;
++ fbi->rgb[RGB_16] = &def_rgb_16;
++
++ inf = pxafb_get_machine_info(fbi);
++
++ fbi->max_xres = inf->xres;
++ fbi->fb.var.xres = inf->xres;
++ fbi->fb.var.xres_virtual = inf->xres;
++ fbi->max_yres = inf->yres;
++ fbi->fb.var.yres = inf->yres;
++ fbi->fb.var.yres_virtual = inf->yres;
++ fbi->max_bpp = inf->bpp;
++ fbi->fb.var.bits_per_pixel = inf->bpp;
++ fbi->fb.var.pixclock = inf->pixclock;
++ fbi->fb.var.hsync_len = inf->hsync_len;
++ fbi->fb.var.left_margin = inf->left_margin;
++ fbi->fb.var.right_margin = inf->right_margin;
++ fbi->fb.var.vsync_len = inf->vsync_len;
++ fbi->fb.var.upper_margin = inf->upper_margin;
++ fbi->fb.var.lower_margin = inf->lower_margin;
++ fbi->fb.var.sync = inf->sync;
++ fbi->fb.var.grayscale = inf->cmap_greyscale;
++ fbi->cmap_inverse = inf->cmap_inverse;
++ fbi->cmap_static = inf->cmap_static;
++ fbi->lccr0 = inf->lccr0;
++ fbi->lccr3 = inf->lccr3;
++ fbi->state = C_DISABLE;
++ fbi->task_state = (u_char)-1;
++ fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres *
++ fbi->max_bpp / 8;
++
++ init_waitqueue_head(&fbi->ctrlr_wait);
++ INIT_TQUEUE(&fbi->task, pxafb_task, fbi);
++ init_MUTEX(&fbi->ctrlr_sem);
++
++ return fbi;
++}
++
++int __init pxafb_init(void)
++{
++ struct pxafb_info *fbi;
++ int ret;
++
++ fbi = pxafb_init_fbinfo();
++ ret = -ENOMEM;
++ if (!fbi)
++ goto failed;
++
++ if(machine_is_pxa_cerf()) {
++ // brightness&contrast is handled via lcdctrl.
++ lcdctrl_init();
++ }
++
++ /* Initialize video memory */
++ ret = pxafb_map_video_memory(fbi);
++ if (ret)
++ goto failed;
++
++ ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT,
++ "LCD", fbi);
++ if (ret) {
++ printk(KERN_ERR "pxafb: failed in request_irq: %d\n", ret);
++ goto failed;
++ }
++
++ pxafb_set_var(&fbi->fb.var, -1, &fbi->fb);
++
++ ret = register_framebuffer(&fbi->fb);
++ if (ret < 0)
++ goto failed;
++
++#ifdef CONFIG_PM
++ /*
++ * Note that the console registers this as well, but we want to
++ * power down the display prior to sleeping.
++ */
++ fbi->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, pxafb_pm_callback);
++ if (fbi->pm)
++ fbi->pm->data = fbi;
++#endif
++#ifdef CONFIG_CPU_FREQ
++ fbi->clockchg.notifier_call = pxafb_clkchg_notifier;
++ cpufreq_register_notifier(&fbi->clockchg);
++#endif
++
++ /*
++ * Ok, now enable the LCD controller
++ */
++ set_ctrlr_state(fbi, C_ENABLE);
++
++ /* This driver cannot be unloaded at the moment */
++ MOD_INC_USE_COUNT;
++
++ return 0;
++
++failed:
++ if (fbi)
++ kfree(fbi);
++ return ret;
++}
++
++
++#ifdef MODULE
++module_init(pxafb_init);
++#endif
++
++MODULE_DESCRIPTION("loadable framebuffer driver for PXA");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ linux-2.4.27/drivers/video/pxafb.h
+@@ -0,0 +1,238 @@
++/*
++ * linux/drivers/video/pxafb.h
++ * -- Intel PXA250/210 LCD Controller Frame Buffer Device
++ *
++ * Copyright (C) 1999 Eric A. Thomas
++ * Based on acornfb.c Copyright (C) Russell King.
++ *
++ * 2001-08-03: Cliff Brake <cbrake@acclent.com>
++ * - ported SA1100 code to PXA
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive
++ * for more details.
++ */
++
++/*
++ * These are the bitfields for each
++ * display depth that we support.
++ */
++struct pxafb_rgb {
++ struct fb_bitfield red;
++ struct fb_bitfield green;
++ struct fb_bitfield blue;
++ struct fb_bitfield transp;
++};
++
++/*
++ * This structure describes the machine which we are running on.
++ */
++struct pxafb_mach_info {
++ u_long pixclock;
++
++ u_short xres;
++ u_short yres;
++
++ u_char bpp;
++ u_char hsync_len;
++ u_char left_margin;
++ u_char right_margin;
++
++ u_char vsync_len;
++ u_char upper_margin;
++ u_char lower_margin;
++ u_char sync;
++
++ u_int cmap_greyscale:1,
++ cmap_inverse:1,
++ cmap_static:1,
++ unused:29;
++
++ u_int lccr0;
++ u_int lccr3;
++};
++
++/* Shadows for LCD controller registers */
++struct pxafb_lcd_reg {
++ unsigned int lccr0;
++ unsigned int lccr1;
++ unsigned int lccr2;
++ unsigned int lccr3;
++};
++
++/* PXA LCD DMA descriptor */
++struct pxafb_dma_descriptor {
++ unsigned int fdadr;
++ unsigned int fsadr;
++ unsigned int fidr;
++ unsigned int ldcmd;
++};
++
++#define RGB_8 (0)
++#define RGB_16 (1)
++#define NR_RGB 2
++
++struct pxafb_info {
++ struct fb_info fb;
++ signed int currcon;
++
++ struct pxafb_rgb *rgb[NR_RGB];
++
++ u_int max_bpp;
++ u_int max_xres;
++ u_int max_yres;
++
++ /*
++ * These are the addresses we mapped
++ * the framebuffer memory region to.
++ */
++
++ /* raw memory addresses */
++ dma_addr_t map_dma; /* physical */
++ u_char * map_cpu; /* virtual */
++ u_int map_size;
++
++ /* addresses of pieces placed in raw buffer */
++ u_char * screen_cpu; /* virtual address of frame buffer */
++ dma_addr_t screen_dma; /* physical address of frame buffer */
++ u16 * palette_cpu; /* virtual address of palette memory */
++ dma_addr_t palette_dma; /* physical address of palette memory */
++ u_int palette_size;
++
++ /* DMA descriptors */
++ struct pxafb_dma_descriptor * dmadesc_fblow_cpu;
++ dma_addr_t dmadesc_fblow_dma;
++ struct pxafb_dma_descriptor * dmadesc_fbhigh_cpu;
++ dma_addr_t dmadesc_fbhigh_dma;
++ struct pxafb_dma_descriptor * dmadesc_palette_cpu;
++ dma_addr_t dmadesc_palette_dma;
++
++ dma_addr_t fdadr0;
++ dma_addr_t fdadr1;
++
++ u_int lccr0;
++ u_int lccr3;
++ u_int cmap_inverse:1,
++ cmap_static:1,
++ unused:30;
++
++ u_int reg_lccr0;
++ u_int reg_lccr1;
++ u_int reg_lccr2;
++ u_int reg_lccr3;
++
++ volatile u_char state;
++ volatile u_char task_state;
++ struct semaphore ctrlr_sem;
++ wait_queue_head_t ctrlr_wait;
++ struct tq_struct task;
++
++#ifdef CONFIG_PM
++ struct pm_dev *pm;
++#endif
++#ifdef CONFIG_CPU_FREQ
++ struct notifier_block clockchg;
++#endif
++};
++
++#define __type_entry(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member)))
++
++#define TO_INF(ptr,member) __type_entry(ptr,struct pxafb_info,member)
++
++/*
++ * These are the actions for set_ctrlr_state
++ */
++#define C_DISABLE (0)
++#define C_ENABLE (1)
++#define C_DISABLE_CLKCHANGE (2)
++#define C_ENABLE_CLKCHANGE (3)
++#define C_REENABLE (4)
++
++#define PXA_NAME "PXA"
++
++/*
++ * Debug macros
++ */
++#if DEBUG
++# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
++#else
++# define DPRINTK(fmt, args...)
++#endif
++
++/*
++ * Minimum X and Y resolutions
++ */
++#define MIN_XRES 64
++#define MIN_YRES 64
++
++/*
++ * Are we configured for 8 or 16 bits per pixel?
++ */
++#ifdef CONFIG_FB_PXA_8BPP
++# define PXAFB_BPP 8
++# define PXAFB_BPP_BITS 0x03
++#elif CONFIG_FB_PXA_16BPP
++# define PXAFB_BPP 16
++# define PXAFB_BPP_BITS 0x04
++#endif
++
++#if defined(CONFIG_ARCH_LUBBOCK)
++#define LCD_PIXCLOCK 150000
++#define LCD_BPP PXAFB_BPP
++#ifdef CONFIG_FB_PXA_QVGA
++#define LCD_XRES 320
++#define LCD_YRES 240
++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 51
++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 1
++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 1
++#define LCD_BEGIN_FRAME_WAIT_COUNT 8
++#define LCD_END_OF_LINE_WAIT_COUNT 1
++#define LCD_END_OF_FRAME_WAIT_COUNT 1
++#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT)
++#define LCD_LCCR0 0x003008F8
++#define LCD_LCCR3 (0x0040FF0C | (PXAFB_BPP_BITS << 24))
++#else
++#define LCD_XRES 640
++#define LCD_YRES 480
++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 1
++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 1
++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 3
++#define LCD_BEGIN_FRAME_WAIT_COUNT 0
++#define LCD_END_OF_LINE_WAIT_COUNT 3
++#define LCD_END_OF_FRAME_WAIT_COUNT 0
++#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT)
++#define LCD_LCCR0 0x0030087C
++#define LCD_LCCR3 (0x0040FF0C | (PXAFB_BPP_BITS << 24))
++#endif
++
++#elif defined (CONFIG_ARCH_PXA_IDP)
++#define LCD_PIXCLOCK 150000
++#define LCD_BPP PXAFB_BPP
++#define LCD_XRES 640
++#define LCD_YRES 480
++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 1
++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 1
++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 3
++#define LCD_BEGIN_FRAME_WAIT_COUNT 0
++#define LCD_END_OF_LINE_WAIT_COUNT 3
++#define LCD_END_OF_FRAME_WAIT_COUNT 0
++#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT)
++#define LCD_LCCR0 0x0030087C
++#define LCD_LCCR3 (0x0040FF0C | (PXAFB_BPP_BITS << 24))
++
++#elif defined CONFIG_PXA_CERF_PDA
++#define LCD_PIXCLOCK 171521
++#define LCD_BPP PXAFB_BPP
++#define LCD_XRES 240
++#define LCD_YRES 320
++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 7
++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 2
++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 17
++#define LCD_BEGIN_FRAME_WAIT_COUNT 0
++#define LCD_END_OF_LINE_WAIT_COUNT 17
++#define LCD_END_OF_FRAME_WAIT_COUNT 0
++#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT)
++#define LCD_LCCR0 (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_QDM | LCCR0_BM | LCCR0_OUM)
++#define LCD_LCCR3 (LCCR3_PCP | LCCR3_PixClkDiv(0x12) | LCCR3_Bpp(PXAFB_BPP_BITS) | LCCR3_Acb(0x18))
++
++#endif
+--- linux-2.4.27/drivers/video/sa1100fb.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/drivers/video/sa1100fb.c
+@@ -2175,7 +2175,7 @@
+ */
+ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+ fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
+- &fbi->map_dma);
++ &fbi->map_dma, PTE_BUFFERABLE);
+
+ if (fbi->map_cpu) {
+ fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
+--- linux-2.4.27/fs/Config.in~2.4.27-vrs1-pxa1
++++ linux-2.4.27/fs/Config.in
+@@ -51,6 +51,9 @@
+ int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0
+ fi
+ tristate 'Compressed ROM file system support' CONFIG_CRAMFS
++dep_mbool ' Use linear addressing for cramfs' CONFIG_CRAMFS_LINEAR $CONFIG_CRAMFS
++dep_bool ' Support XIP on linear cramfs' CONFIG_CRAMFS_LINEAR_XIP $CONFIG_CRAMFS_LINEAR
++dep_bool ' Root file system on linear cramfs' CONFIG_ROOT_CRAMFS_LINEAR $CONFIG_CRAMFS_LINEAR
+ bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
+ define_bool CONFIG_RAMFS y
+
+--- linux-2.4.27/fs/cramfs/inode.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/fs/cramfs/inode.c
+@@ -4,11 +4,29 @@
+ * Copyright (C) 1999 Linus Torvalds.
+ *
+ * This file is released under the GPL.
+- */
+-
+-/*
++ *
+ * These are the VFS interfaces to the compressed rom filesystem.
+ * The actual compression is based on zlib, see the other files.
++ *
++ * Linear Addressing code
++ * Copyright (C) 2000 Shane Nay.
++ *
++ * Allows you to have a linearly addressed cramfs filesystem.
++ * Saves the need for buffer, and the munging of the buffer.
++ * Savings a bit over 32k with default PAGE_SIZE, BUFFER_SIZE
++ * etc. Usefull on embedded platform with ROM :-).
++ *
++ * Downsides- Currently linear addressed cramfs partitions
++ * don't co-exist with block cramfs partitions.
++ *
++ * 28-Dec-2000: XIP mode for linear cramfs
++ * Copyright (C) 2000 Robert Leslie <rob@mars.org>
++ *
++ * Dynamic allocation of linear cramfs space by Nicolas Pitre
++ * Copyright (C) 2003 Monta Vista Software, Inc.
++ *
++ * Linear cramfs now requires that you pass the physaddr= parameter to
++ * the mount process. Allows for multiple linear cramfs partitions.
+ */
+
+ #include <linux/module.h>
+@@ -16,10 +34,12 @@
+ #include <linux/pagemap.h>
+ #include <linux/init.h>
+ #include <linux/string.h>
++#include <linux/kernel.h>
+ #include <linux/locks.h>
+ #include <linux/blkdev.h>
+ #include <linux/cramfs_fs.h>
+ #include <asm/semaphore.h>
++#include <asm/io.h>
+
+ #include <asm/uaccess.h>
+
+@@ -28,6 +48,8 @@
+ #define CRAMFS_SB_BLOCKS u.cramfs_sb.blocks
+ #define CRAMFS_SB_FILES u.cramfs_sb.files
+ #define CRAMFS_SB_FLAGS u.cramfs_sb.flags
++#define CRAMFS_SB_LINEAR_PHYS_ADDR u.cramfs_sb.linear_phys_addr
++#define CRAMFS_SB_LINEAR_VIRT_ADDR u.cramfs_sb.linear_virt_addr
+
+ static struct super_operations cramfs_ops;
+ static struct inode_operations cramfs_dir_inode_operations;
+@@ -42,6 +64,74 @@
+ #define CRAMINO(x) ((x)->offset?(x)->offset<<2:1)
+ #define OFFSET(x) ((x)->i_ino)
+
++
++#ifdef CONFIG_CRAMFS_LINEAR_XIP
++
++static int cramfs_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ unsigned long address, length;
++ struct inode *inode = file->f_dentry->d_inode;
++ struct super_block *sb = inode->i_sb;
++
++ /* this is only used in the case of read-only maps for XIP */
++
++ if (vma->vm_flags & VM_WRITE)
++ return generic_file_mmap(file, vma);
++
++ if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
++ return -EINVAL;
++
++ address = PAGE_ALIGN(sb->CRAMFS_SB_LINEAR_PHYS_ADDR + OFFSET(inode));
++ address += vma->vm_pgoff << PAGE_SHIFT;
++
++ length = vma->vm_end - vma->vm_start;
++
++ if (length > inode->i_size)
++ length = inode->i_size;
++
++ length = PAGE_ALIGN(length);
++
++
++#if 0
++ /* Doing the following makes it slower and more broken. bdl */
++ /*
++ * Accessing memory above the top the kernel knows about or
++ * through a file pointer that was marked O_SYNC will be
++ * done non-cached.
++ */
++ vma->vm_page_prot =
++ __pgprot((pgprot_val(vma->vm_page_prot) & ~_CACHE_MASK)
++ | _CACHE_UNCACHED);
++#endif
++
++ /*
++ * Don't dump addresses that are not real memory to a core file.
++ */
++ vma->vm_flags |= VM_IO;
++ flush_tlb_page(vma, address);
++ if (remap_page_range(vma->vm_start, address, length,
++ vma->vm_page_prot))
++ return -EAGAIN;
++
++#ifdef DEBUG_CRAMFS_XIP
++ printk("cramfs_mmap: mapped %s at 0x%08lx, length %lu to vma 0x%08lx"
++ ", page_prot 0x%08lx\n",
++ file->f_dentry->d_name.name, address, length,
++ vma->vm_start, pgprot_val(vma->vm_page_prot));
++#endif
++
++ return 0;
++}
++
++static struct file_operations cramfs_linear_xip_fops = {
++ read: generic_file_read,
++ mmap: cramfs_mmap,
++};
++
++#define CRAMFS_INODE_IS_XIP(x) ((x)->i_mode & S_ISVTX)
++
++#endif
++
+ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode)
+ {
+ struct inode * inode = new_inode(sb);
+@@ -60,7 +150,11 @@
+ without -noleaf option. */
+ insert_inode_hash(inode);
+ if (S_ISREG(inode->i_mode)) {
++#ifdef CONFIG_CRAMFS_LINEAR_XIP
++ inode->i_fop = CRAMFS_INODE_IS_XIP(inode) ? &cramfs_linear_xip_fops : &generic_ro_fops;
++#else
+ inode->i_fop = &generic_ro_fops;
++#endif
+ inode->i_data.a_ops = &cramfs_aops;
+ } else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &cramfs_dir_inode_operations;
+@@ -76,6 +170,18 @@
+ return inode;
+ }
+
++#ifdef CONFIG_CRAMFS_LINEAR
++/*
++ * Return a pointer to the block in the linearly addressed cramfs image.
++ */
++static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)
++{
++ if (!len)
++ return NULL;
++ return (void*)(sb->CRAMFS_SB_LINEAR_VIRT_ADDR + offset);
++}
++
++#else /* Not linear addressing - aka regular block mode. */
+ /*
+ * We have our own block cache: don't fill up the buffer cache
+ * with the rom-image, because the way the filesystem is set
+@@ -192,19 +298,59 @@
+ }
+ return read_buffers[buffer] + offset;
+ }
+-
++#endif /* !CONFIG_CRAMFS_LINEAR */
+
+ static struct super_block * cramfs_read_super(struct super_block *sb, void *data, int silent)
+ {
++#ifndef CONFIG_CRAMFS_LINEAR
+ int i;
++#else
++ char *p;
++#endif
+ struct cramfs_super super;
+ unsigned long root_offset;
+ struct super_block * retval = NULL;
+
++#ifndef CONFIG_CRAMFS_LINEAR
+ /* Invalidate the read buffers on mount: think disk change.. */
+ for (i = 0; i < READ_BUFFERS; i++)
+ buffer_blocknr[i] = -1;
+
++#else
++
++ /*
++ * The physical location of the cramfs image is specified as
++ * a mount parameter. This parameter is mandatory for obvious
++ * reasons. Some validation is made on the phys address but this
++ * is not exhaustive and we count on the fact that someone using
++ * this feature is supposed to know what he/she's doing.
++ */
++ if (!data || !(p = strstr((char *)data, "physaddr="))) {
++ printk(KERN_ERR "cramfs: unknown physical address for linear cramfs image\n");
++ goto out;
++ }
++ sb->CRAMFS_SB_LINEAR_PHYS_ADDR = simple_strtoul(p + 9, NULL, 0);
++ if (sb->CRAMFS_SB_LINEAR_PHYS_ADDR & (PAGE_SIZE-1)) {
++ printk(KERN_ERR "cramfs: physical address 0x%lx for linear cramfs isn't aligned to a page boundary\n",
++ sb->CRAMFS_SB_LINEAR_PHYS_ADDR);
++ goto out;
++ }
++ if (sb->CRAMFS_SB_LINEAR_PHYS_ADDR == 0) {
++ printk(KERN_ERR "cramfs: physical address for linear cramfs image can't be 0\n");
++ goto out;
++ }
++ printk(KERN_INFO "cramfs: checking physical address 0x%lx for linear cramfs image\n",
++ sb->CRAMFS_SB_LINEAR_PHYS_ADDR);
++
++ /* Map only one page for now. Will remap it when fs size is known. */
++ sb->CRAMFS_SB_LINEAR_VIRT_ADDR =
++ ioremap(sb->CRAMFS_SB_LINEAR_PHYS_ADDR, PAGE_SIZE);
++ if (!sb->CRAMFS_SB_LINEAR_VIRT_ADDR) {
++ printk(KERN_ERR "cramfs: ioremap of the linear cramfs image failed\n");
++ goto out;
++ }
++#endif
++
+ down(&read_mutex);
+ /* Read the first block and get the superblock from it */
+ memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));
+@@ -256,8 +402,26 @@
+ /* Set it all up.. */
+ sb->s_op = &cramfs_ops;
+ sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root));
++
++#ifdef CONFIG_CRAMFS_LINEAR
++ /* Remap the whole filesystem now */
++ iounmap(sb->CRAMFS_SB_LINEAR_VIRT_ADDR);
++ printk(KERN_INFO "cramfs: linear cramfs image appears to be %lu KB in size\n",
++ sb->CRAMFS_SB_SIZE/1024);
++ sb->CRAMFS_SB_LINEAR_VIRT_ADDR =
++ ioremap(sb->CRAMFS_SB_LINEAR_PHYS_ADDR, sb->CRAMFS_SB_SIZE);
++ if (!sb->CRAMFS_SB_LINEAR_VIRT_ADDR) {
++ printk(KERN_ERR "cramfs: ioremap of the linear cramfs image failed\n");
++ goto out;
++ }
++#endif
++
+ retval = sb;
+ out:
++#ifdef CONFIG_CRAMFS_LINEAR
++ if (!retval && sb->CRAMFS_SB_LINEAR_VIRT_ADDR)
++ iounmap(sb->CRAMFS_SB_LINEAR_VIRT_ADDR);
++#endif
+ return retval;
+ }
+
+@@ -390,6 +554,18 @@
+
+ maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ bytes_filled = 0;
++#ifdef CONFIG_CRAMFS_LINEAR_XIP
++ if (page->index < maxblock && CRAMFS_INODE_IS_XIP(inode)) {
++ struct super_block *sb = inode->i_sb;
++ u32 blkptr_offset = PAGE_ALIGN(OFFSET(inode)) +
++ page->index * PAGE_CACHE_SIZE;
++ memcpy( page_address(page),
++ (void*)(sb->CRAMFS_SB_LINEAR_VIRT_ADDR + blkptr_offset),
++ PAGE_CACHE_SIZE );
++ bytes_filled = PAGE_CACHE_SIZE;
++ pgdata = kmap(page);
++ } else
++#endif
+ if (page->index < maxblock) {
+ struct super_block *sb = inode->i_sb;
+ u32 blkptr_offset = OFFSET(inode) + page->index*4;
+@@ -446,7 +622,11 @@
+ statfs: cramfs_statfs,
+ };
+
++#ifndef CONFIG_CRAMFS_LINEAR
+ static DECLARE_FSTYPE_DEV(cramfs_fs_type, "cramfs", cramfs_read_super);
++#else
++static DECLARE_FSTYPE(cramfs_fs_type, "cramfs", cramfs_read_super, 0);
++#endif
+
+ static int __init init_cramfs_fs(void)
+ {
+--- /dev/null
++++ linux-2.4.27/fs/cramfs/mkcramfs.c
+@@ -0,0 +1,821 @@
++/*
++ * mkcramfs - make a cramfs file system, optionally with XIP files.
++ *
++ * Copyright (C) 1999-2001 Transmeta Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <sys/types.h>
++#include <stdio.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <sys/mman.h>
++#include <sys/fcntl.h>
++#include <dirent.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#include <assert.h>
++#include <getopt.h>
++#include <linux/cramfs_fs.h>
++#include <zlib.h>
++
++#define PAD_SIZE 512 /* only 0 and 512 supported by kernel */
++
++static const char *progname = "mkcramfs";
++
++/* N.B. If you change the disk format of cramfs, please update fs/cramfs/README. */
++
++/* Input status of 0 to print help and exit without an error. */
++static void usage(int status)
++{
++ FILE *stream = status ? stderr : stdout;
++
++ fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] dirname outfile\n"
++ " -h print this help\n"
++ " -E make all warnings errors (non-zero exit status)\n"
++ " -e edition set edition number (part of fsid)\n"
++ " -i file insert a file image into the filesystem (requires >= 2.4.0)\n"
++ " -n name set name of cramfs filesystem\n"
++ " -p pad by %d bytes for boot code\n"
++ " -s sort directory entries (old option, ignored)\n"
++ " -x make marked files eXecute In Place\n"
++ " -z make explicit holes (requires >= 2.3.39)\n"
++ " dirname root of the filesystem to be compressed\n"
++ " outfile output file\n", progname, PAD_SIZE);
++
++ exit(status);
++}
++
++#define PAGE_SIZE (4096)
++#define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
++#define ROM_OFFSET 0
++#define ROM_ALIGN(x) (PAGE_ALIGN((x) + ROM_OFFSET) - ROM_OFFSET)
++#define PAGE_CACHE_SIZE (4096)
++/* The kernel assumes PAGE_CACHE_SIZE as block size. */
++static unsigned int blksize = PAGE_CACHE_SIZE;
++static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */
++static int image_length = 0;
++
++/*
++ * If opt_holes is set, then mkcramfs can create explicit holes in the
++ * data, which saves 26 bytes per hole (which is a lot smaller a
++ * saving than most most filesystems).
++ *
++ * Note that kernels up to at least 2.3.39 don't support cramfs holes,
++ * which is why this is turned off by default.
++ */
++static int opt_edition = 0;
++static int opt_errors = 0;
++static int opt_holes = 0;
++static int opt_xip = 0;
++static int opt_pad = 0;
++static char *opt_image = NULL;
++static char *opt_name = NULL;
++
++static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid;
++
++#ifndef MIN
++# define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
++#endif
++
++/* In-core version of inode / directory entry. */
++struct entry {
++ /* stats */
++ char *name;
++ unsigned int mode, size, uid, gid;
++
++ /* FS data */
++ void *uncompressed;
++ /* points to other identical file */
++ struct entry *same;
++ unsigned int offset; /* pointer to compressed data in archive */
++ unsigned int dir_offset; /* Where in the archive is the directory entry? */
++
++ /* organization */
++ struct entry *child; /* null for non-directories and empty directories */
++ struct entry *next;
++};
++
++/*
++ * The longest file name component to allow for in the input directory tree.
++ * Ext2fs (and many others) allow up to 255 bytes. A couple of filesystems
++ * allow longer (e.g. smbfs 1024), but there isn't much use in supporting
++ * >255-byte names in the input directory tree given that such names get
++ * truncated to 255 bytes when written to cramfs.
++ */
++#define MAX_INPUT_NAMELEN 255
++
++static int find_identical_file(struct entry *orig,struct entry *newfile)
++{
++ if(orig==newfile) return 1;
++ if(!orig) return 0;
++ if(orig->size==newfile->size && orig->uncompressed && !memcmp(orig->uncompressed,newfile->uncompressed,orig->size)) {
++ newfile->same=orig;
++ return 1;
++ }
++ return find_identical_file(orig->child,newfile) ||
++ find_identical_file(orig->next,newfile);
++}
++
++static void eliminate_doubles(struct entry *root,struct entry *orig) {
++ if(orig) {
++ if(orig->size && orig->uncompressed)
++ find_identical_file(root,orig);
++ eliminate_doubles(root,orig->child);
++ eliminate_doubles(root,orig->next);
++ }
++}
++
++/*
++ * We define our own sorting function instead of using alphasort which
++ * uses strcoll and changes ordering based on locale information.
++ */
++static int cramsort (const void *a, const void *b)
++{
++ return strcmp ((*(const struct dirent **) a)->d_name,
++ (*(const struct dirent **) b)->d_name);
++}
++
++static unsigned int parse_directory(struct entry *root_entry, const char *name, struct entry **prev, loff_t *fslen_ub)
++{
++ struct dirent **dirlist;
++ int totalsize = 0, dircount, dirindex;
++ char *path, *endpath;
++ size_t len = strlen(name);
++
++ /* Set up the path. */
++ /* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */
++ path = malloc(len + 1 + MAX_INPUT_NAMELEN + 1);
++ if (!path) {
++ perror(NULL);
++ exit(8);
++ }
++ memcpy(path, name, len);
++ endpath = path + len;
++ *endpath = '/';
++ endpath++;
++
++ /* read in the directory and sort */
++ dircount = scandir(name, &dirlist, 0, cramsort);
++
++ if (dircount < 0) {
++ perror(name);
++ exit(8);
++ }
++
++ /* process directory */
++ for (dirindex = 0; dirindex < dircount; dirindex++) {
++ struct dirent *dirent;
++ struct entry *entry;
++ struct stat st;
++ int size;
++ size_t namelen;
++
++ dirent = dirlist[dirindex];
++
++ /* Ignore "." and ".." - we won't be adding them to the archive */
++ if (dirent->d_name[0] == '.') {
++ if (dirent->d_name[1] == '\0')
++ continue;
++ if (dirent->d_name[1] == '.') {
++ if (dirent->d_name[2] == '\0')
++ continue;
++ }
++ }
++ namelen = strlen(dirent->d_name);
++ if (namelen > MAX_INPUT_NAMELEN) {
++ fprintf(stderr,
++ "Very long (%u bytes) filename `%s' found.\n"
++ " Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile. Exiting.\n",
++ namelen, dirent->d_name);
++ exit(8);
++ }
++ memcpy(endpath, dirent->d_name, namelen + 1);
++
++ if (lstat(path, &st) < 0) {
++ perror(endpath);
++ warn_skip = 1;
++ continue;
++ }
++ entry = calloc(1, sizeof(struct entry));
++ if (!entry) {
++ perror(NULL);
++ exit(8);
++ }
++ entry->name = strdup(dirent->d_name);
++ if (!entry->name) {
++ perror(NULL);
++ exit(8);
++ }
++ if (namelen > 255) {
++ /* Can't happen when reading from ext2fs. */
++
++ /* TODO: we ought to avoid chopping in half
++ multi-byte UTF8 characters. */
++ entry->name[namelen = 255] = '\0';
++ warn_namelen = 1;
++ }
++ entry->mode = st.st_mode;
++ entry->size = st.st_size;
++ entry->uid = st.st_uid;
++ if (entry->uid >= 1 << CRAMFS_UID_WIDTH)
++ warn_uid = 1;
++ entry->gid = st.st_gid;
++ if (entry->gid >= 1 << CRAMFS_GID_WIDTH)
++ /* TODO: We ought to replace with a default
++ gid instead of truncating; otherwise there
++ are security problems. Maybe mode should
++ be &= ~070. Same goes for uid once Linux
++ supports >16-bit uids. */
++ warn_gid = 1;
++ size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
++ *fslen_ub += size;
++ if (S_ISDIR(st.st_mode)) {
++ entry->size = parse_directory(root_entry, path, &entry->child, fslen_ub);
++ } else if (S_ISREG(st.st_mode)) {
++ /* TODO: We ought to open files in do_compress, one
++ at a time, instead of amassing all these memory
++ maps during parse_directory (which don't get used
++ until do_compress anyway). As it is, we tend to
++ get EMFILE errors (especially if mkcramfs is run
++ by non-root).
++
++ While we're at it, do analagously for symlinks
++ (which would just save a little memory). */
++ int fd = open(path, O_RDONLY);
++ if (fd < 0) {
++ perror(path);
++ warn_skip = 1;
++ continue;
++ }
++ if (entry->size) {
++ if ((entry->size >= 1 << CRAMFS_SIZE_WIDTH)) {
++ warn_size = 1;
++ entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1;
++ }
++
++ entry->uncompressed = mmap(NULL, entry->size, PROT_READ, MAP_PRIVATE, fd, 0);
++ if (-1 == (int) (long) entry->uncompressed) {
++ perror("mmap");
++ exit(8);
++ }
++ }
++ close(fd);
++ } else if (S_ISLNK(st.st_mode)) {
++ entry->uncompressed = malloc(entry->size);
++ if (!entry->uncompressed) {
++ perror(NULL);
++ exit(8);
++ }
++ if (readlink(path, entry->uncompressed, entry->size) < 0) {
++ perror(path);
++ warn_skip = 1;
++ continue;
++ }
++ } else if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
++ /* maybe we should skip sockets */
++ entry->size = 0;
++ } else {
++ entry->size = st.st_rdev;
++ if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))
++ warn_dev = 1;
++ }
++
++ if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
++ int blocks = ((entry->size - 1) / blksize + 1);
++
++ /* block pointers & data expansion allowance + data */
++ if(entry->size)
++ *fslen_ub += (4+26)*blocks + entry->size + 3;
++ }
++
++ if (opt_xip && entry->mode & S_ISVTX) {
++ /* worse case, depending on where the offsets falls,
++ * a single XIP entry could expand the sizeof the
++ * file system by 8k, since we're aligning the start
++ * and end on page boundary.
++ */
++ *fslen_ub += 2*PAGE_CACHE_SIZE;
++ }
++
++ /* Link it into the list */
++ *prev = entry;
++ prev = &entry->next;
++ totalsize += size;
++ }
++ free(path);
++ free(dirlist); /* allocated by scandir() with malloc() */
++ return totalsize;
++}
++
++/* Returns sizeof(struct cramfs_super), which includes the root inode. */
++static unsigned int write_superblock(struct entry *root, char *base, int size)
++{
++ struct cramfs_super *super = (struct cramfs_super *) base;
++ unsigned int offset = sizeof(struct cramfs_super) + image_length;
++
++ if (opt_pad) {
++ offset += opt_pad;
++ }
++
++ super->magic = CRAMFS_MAGIC;
++ super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS;
++ if (opt_holes)
++ super->flags |= CRAMFS_FLAG_HOLES;
++ if (image_length > 0)
++ super->flags |= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET;
++ super->size = size;
++ memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature));
++
++ super->fsid.crc = crc32(0L, Z_NULL, 0);
++ super->fsid.edition = opt_edition;
++ super->fsid.blocks = total_blocks;
++ super->fsid.files = total_nodes;
++
++ memset(super->name, 0x00, sizeof(super->name));
++ if (opt_name)
++ strncpy(super->name, opt_name, sizeof(super->name));
++ else
++ strncpy(super->name, "Compressed", sizeof(super->name));
++
++ super->root.mode = root->mode;
++ super->root.uid = root->uid;
++ super->root.gid = root->gid;
++ super->root.size = root->size;
++ super->root.offset = offset >> 2;
++
++ return offset;
++}
++
++static void set_data_offset(struct entry *entry, char *base, unsigned long offset)
++{
++ struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
++#ifdef DEBUG
++ assert ((offset & 3) == 0);
++#endif /* DEBUG */
++ if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
++ fprintf(stderr, "filesystem too big. Exiting.\n");
++ exit(8);
++ }
++ inode->offset = (offset >> 2);
++}
++
++
++/*
++ * We do a width-first printout of the directory
++ * entries, using a stack to remember the directories
++ * we've seen.
++ */
++#define MAXENTRIES (100)
++static unsigned int write_directory_structure(struct entry *entry, char *base, unsigned int offset)
++{
++ int stack_entries = 0;
++ struct entry *entry_stack[MAXENTRIES];
++
++ for (;;) {
++ int dir_start = stack_entries;
++ while (entry) {
++ struct cramfs_inode *inode = (struct cramfs_inode *) (base + offset);
++ size_t len = strlen(entry->name);
++
++ entry->dir_offset = offset;
++
++ inode->mode = entry->mode;
++ inode->uid = entry->uid;
++ inode->gid = entry->gid;
++ inode->size = entry->size;
++ inode->offset = 0;
++ /* Non-empty directories, regfiles and symlinks will
++ write over inode->offset later. */
++
++ offset += sizeof(struct cramfs_inode);
++ total_nodes++; /* another node */
++ memcpy(base + offset, entry->name, len);
++ /* Pad up the name to a 4-byte boundary */
++ while (len & 3) {
++ *(base + offset + len) = '\0';
++ len++;
++ }
++ inode->namelen = len >> 2;
++ offset += len;
++
++ /* TODO: this may get it wrong for chars >= 0x80.
++ Most filesystems use UTF8 encoding for filenames,
++ whereas the console is a single-byte character
++ set like iso-latin-1. */
++ printf(" %s\n", entry->name);
++ if (entry->child) {
++ if (stack_entries >= MAXENTRIES) {
++ fprintf(stderr, "Exceeded MAXENTRIES. Raise this value in mkcramfs.c and recompile. Exiting.\n");
++ exit(8);
++ }
++ entry_stack[stack_entries] = entry;
++ stack_entries++;
++ }
++ entry = entry->next;
++ }
++
++ /*
++ * Reverse the order the stack entries pushed during
++ * this directory, for a small optimization of disk
++ * access in the created fs. This change makes things
++ * `ls -UR' order.
++ */
++ {
++ struct entry **lo = entry_stack + dir_start;
++ struct entry **hi = entry_stack + stack_entries;
++ struct entry *tmp;
++
++ while (lo < --hi) {
++ tmp = *lo;
++ *lo++ = *hi;
++ *hi = tmp;
++ }
++ }
++
++ /* Pop a subdirectory entry from the stack, and recurse. */
++ if (!stack_entries)
++ break;
++ stack_entries--;
++ entry = entry_stack[stack_entries];
++
++ set_data_offset(entry, base, offset);
++ printf("'%s':\n", entry->name);
++ entry = entry->child;
++ }
++ return offset;
++}
++
++static int is_zero(char const *begin, unsigned len)
++{
++ if (opt_holes)
++ /* Returns non-zero iff the first LEN bytes from BEGIN are
++ all NULs. */
++ return (len-- == 0 ||
++ (begin[0] == '\0' &&
++ (len-- == 0 ||
++ (begin[1] == '\0' &&
++ (len-- == 0 ||
++ (begin[2] == '\0' &&
++ (len-- == 0 ||
++ (begin[3] == '\0' &&
++ memcmp(begin, begin + 4, len) == 0))))))));
++ else
++ /* Never create holes. */
++ return 0;
++}
++
++static unsigned int do_xip(char *base, unsigned int offset,
++ char const *name, char *uncompressed,
++ unsigned int size)
++{
++ unsigned int start, end;
++
++ /* align to page boundary */
++
++ start = ROM_ALIGN(offset);
++ memset(base + offset, 0, start - offset);
++
++ memcpy(base + start, uncompressed, size);
++
++ /* pad to page boundary */
++
++ end = ROM_ALIGN(start + size);
++ memset(base + start + size, 0, end - (start + size));
++
++ printf("XIP (%u+%u bytes)\toffset %u\t%s\n",
++ size, (end - offset) - size, offset, name);
++
++ return end;
++}
++
++/*
++ * One 4-byte pointer per block and then the actual blocked
++ * output. The first block does not need an offset pointer,
++ * as it will start immediately after the pointer block;
++ * so the i'th pointer points to the end of the i'th block
++ * (i.e. the start of the (i+1)'th block or past EOF).
++ *
++ * Note that size > 0, as a zero-sized file wouldn't ever
++ * have gotten here in the first place.
++ */
++static unsigned int do_compress(char *base, unsigned int offset, char const *name, char *uncompressed, unsigned int size)
++{
++ unsigned long original_size = size;
++ unsigned long original_offset = offset;
++ unsigned long new_size;
++ unsigned long blocks = (size - 1) / blksize + 1;
++ unsigned long curr = offset + 4 * blocks;
++ int change;
++
++ total_blocks += blocks;
++
++ do {
++ unsigned long len = 2 * blksize;
++ unsigned int input = size;
++ if (input > blksize)
++ input = blksize;
++ size -= input;
++ if (!is_zero (uncompressed, input)) {
++ compress(base + curr, &len, uncompressed, input);
++ curr += len;
++ }
++ uncompressed += input;
++
++ if (len > blksize*2) {
++ /* (I don't think this can happen with zlib.) */
++ printf("AIEEE: block \"compressed\" to > 2*blocklength (%ld)\n", len);
++ exit(8);
++ }
++
++ *(u32 *) (base + offset) = curr;
++ offset += 4;
++ } while (size);
++
++ curr = (curr + 3) & ~3;
++ new_size = curr - original_offset;
++ /* TODO: Arguably, original_size in these 2 lines should be
++ st_blocks * 512. But if you say that then perhaps
++ administrative data should also be included in both. */
++ change = new_size - original_size;
++ printf("%6.2f%% (%+d bytes)\toffset %lu\t%s\n",
++ (change * 100) / (double) original_size, change, original_offset, name);
++
++ return curr;
++}
++
++
++/*
++ * Traverse the entry tree, writing data for every item that has
++ * non-null entry->compressed (i.e. every symlink and non-empty
++ * regfile).
++ */
++static unsigned int write_data(struct entry *entry, char *base, unsigned int offset)
++{
++ do {
++ if (entry->uncompressed) {
++ if(entry->same) {
++ set_data_offset(entry, base, entry->same->offset);
++ entry->offset=entry->same->offset;
++ } else {
++ set_data_offset(entry, base, offset);
++ entry->offset=offset;
++ if (opt_xip && entry->mode & S_ISVTX)
++ offset = do_xip(base, offset, entry->name, entry->uncompressed, entry->size);
++ else
++ offset = do_compress(base, offset, entry->name, entry->uncompressed, entry->size);
++ }
++ }
++ else if (entry->child)
++ offset = write_data(entry->child, base, offset);
++ entry=entry->next;
++ } while (entry);
++ return offset;
++}
++
++static unsigned int write_file(char *file, char *base, unsigned int offset)
++{
++ int fd;
++ char *buf;
++
++ fd = open(file, O_RDONLY);
++ if (fd < 0) {
++ perror(file);
++ exit(8);
++ }
++ buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0);
++ memcpy(base + offset, buf, image_length);
++ munmap(buf, image_length);
++ close (fd);
++ /* Pad up the image_length to a 4-byte boundary */
++ while (image_length & 3) {
++ *(base + offset + image_length) = '\0';
++ image_length++;
++ }
++ return (offset + image_length);
++}
++
++/*
++ * Maximum size fs you can create is roughly 256MB. (The last file's
++ * data must begin within 256MB boundary but can extend beyond that.)
++ *
++ * Note that if you want it to fit in a ROM then you're limited to what the
++ * hardware and kernel can support (64MB?).
++ */
++#define MAXFSLEN ((((1 << CRAMFS_OFFSET_WIDTH) - 1) << 2) /* offset */ \
++ + (1 << CRAMFS_SIZE_WIDTH) - 1 /* filesize */ \
++ + (1 << CRAMFS_SIZE_WIDTH) * 4 / PAGE_CACHE_SIZE /* block pointers */ )
++
++
++/*
++ * Usage:
++ *
++ * mkcramfs directory-name outfile
++ *
++ * where "directory-name" is simply the root of the directory
++ * tree that we want to generate a compressed filesystem out
++ * of.
++ */
++int main(int argc, char **argv)
++{
++ struct stat st; /* used twice... */
++ struct entry *root_entry;
++ char *rom_image;
++ ssize_t offset, written;
++ int fd;
++ /* initial guess (upper-bound) of required filesystem size */
++ loff_t fslen_ub = sizeof(struct cramfs_super);
++ char const *dirname, *outfile;
++ u32 crc = crc32(0L, Z_NULL, 0);
++ int c; /* for getopt */
++
++ total_blocks = 0;
++
++ if (argc)
++ progname = argv[0];
++
++ /* command line options */
++ while ((c = getopt(argc, argv, "hEe:i:n:psxz")) != EOF) {
++ switch (c) {
++ case 'h':
++ usage(0);
++ case 'E':
++ opt_errors = 1;
++ break;
++ case 'e':
++ opt_edition = atoi(optarg);
++ break;
++ case 'i':
++ opt_image = optarg;
++ if (lstat(opt_image, &st) < 0) {
++ perror(opt_image);
++ exit(16);
++ }
++ image_length = st.st_size; /* may be padded later */
++ fslen_ub += (image_length + 3); /* 3 is for padding */
++ break;
++ case 'n':
++ opt_name = optarg;
++ break;
++ case 'p':
++ opt_pad = PAD_SIZE;
++ fslen_ub += PAD_SIZE;
++ break;
++ case 's':
++ /* old option, ignored */
++ break;
++ case 'x':
++ opt_xip = 1;
++ break;
++ case 'z':
++ opt_holes = 1;
++ break;
++ }
++ }
++
++ if ((argc - optind) != 2)
++ usage(16);
++ dirname = argv[optind];
++ outfile = argv[optind + 1];
++
++ if (stat(dirname, &st) < 0) {
++ perror(dirname);
++ exit(16);
++ }
++ fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
++
++ root_entry = calloc(1, sizeof(struct entry));
++ if (!root_entry) {
++ perror(NULL);
++ exit(8);
++ }
++ root_entry->mode = st.st_mode;
++ root_entry->uid = st.st_uid;
++ root_entry->gid = st.st_gid;
++
++ root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub);
++
++ /* always allocate a multiple of blksize bytes because that's
++ what we're going to write later on */
++ fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1;
++
++ if (fslen_ub > MAXFSLEN) {
++ fprintf(stderr,
++ "warning: guestimate of required size (upper bound) is %LdMB, but maximum image size is %uMB. We might die prematurely.\n",
++ fslen_ub >> 20,
++ MAXFSLEN >> 20);
++ fslen_ub = MAXFSLEN;
++ }
++
++ /* find duplicate files. TODO: uses the most inefficient algorithm
++ possible. */
++ eliminate_doubles(root_entry,root_entry);
++
++ /* TODO: Why do we use a private/anonymous mapping here
++ followed by a write below, instead of just a shared mapping
++ and a couple of ftruncate calls? Is it just to save us
++ having to deal with removing the file afterwards? If we
++ really need this huge anonymous mapping, we ought to mmap
++ in smaller chunks, so that the user doesn't need nn MB of
++ RAM free. If the reason is to be able to write to
++ un-mmappable block devices, then we could try shared mmap
++ and revert to anonymous mmap if the shared mmap fails. */
++ rom_image = mmap(NULL, fslen_ub?fslen_ub:1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++
++ if (-1 == (int) (long) rom_image) {
++ perror("ROM image map");
++ exit(8);
++ }
++
++ /* Skip the first opt_pad bytes for boot loader code */
++ offset = opt_pad;
++ memset(rom_image, 0x00, opt_pad);
++
++ /* Skip the superblock and come back to write it later. */
++ offset += sizeof(struct cramfs_super);
++
++ /* Insert a file image. */
++ if (opt_image) {
++ printf("Including: %s\n", opt_image);
++ offset = write_file(opt_image, rom_image, offset);
++ }
++
++ offset = write_directory_structure(root_entry->child, rom_image, offset);
++ printf("Directory data: %d bytes\n", offset);
++
++ offset = write_data(root_entry, rom_image, offset);
++
++ /* We always write a multiple of blksize bytes, so that
++ losetup works. */
++ offset = ((offset - 1) | (blksize - 1)) + 1;
++ printf("Everything: %d kilobytes\n", offset >> 10);
++
++ /* Write the superblock now that we can fill in all of the fields. */
++ write_superblock(root_entry, rom_image+opt_pad, offset);
++ printf("Super block: %d bytes\n", sizeof(struct cramfs_super));
++
++ /* Put the checksum in. */
++ crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad));
++ ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc;
++ printf("CRC: %x\n", crc);
++
++ /* Check to make sure we allocated enough space. */
++ if (fslen_ub < offset) {
++ fprintf(stderr, "not enough space allocated for ROM image (%Ld allocated, %d used)\n",
++ fslen_ub, offset);
++ exit(8);
++ }
++
++ written = write(fd, rom_image, offset);
++ if (written < 0) {
++ perror("ROM image");
++ exit(8);
++ }
++ if (offset != written) {
++ fprintf(stderr, "ROM image write failed (%d %d)\n", written, offset);
++ exit(8);
++ }
++
++ /* (These warnings used to come at the start, but they scroll off the
++ screen too quickly.) */
++ if (warn_namelen) /* (can't happen when reading from ext2fs) */
++ fprintf(stderr, /* bytes, not chars: think UTF8. */
++ "warning: filenames truncated to 255 bytes.\n");
++ if (warn_skip)
++ fprintf(stderr, "warning: files were skipped due to errors.\n");
++ if (warn_size)
++ fprintf(stderr,
++ "warning: file sizes truncated to %luMB (minus 1 byte).\n",
++ 1L << (CRAMFS_SIZE_WIDTH - 20));
++ if (warn_uid) /* (not possible with current Linux versions) */
++ fprintf(stderr,
++ "warning: uids truncated to %u bits. (This may be a security concern.)\n",
++ CRAMFS_UID_WIDTH);
++ if (warn_gid)
++ fprintf(stderr,
++ "warning: gids truncated to %u bits. (This may be a security concern.)\n",
++ CRAMFS_GID_WIDTH);
++ if (warn_dev)
++ fprintf(stderr,
++ "WARNING: device numbers truncated to %u bits. This almost certainly means\n"
++ "that some device files will be wrong.\n",
++ CRAMFS_OFFSET_WIDTH);
++ if (opt_errors &&
++ (warn_namelen||warn_skip||warn_size||warn_uid||warn_gid||warn_dev))
++ exit(8);
++ return 0;
++}
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/bitfield.h
+@@ -0,0 +1,113 @@
++/*
++ * FILE bitfield.h
++ *
++ * Version 1.1
++ * Author Copyright (c) Marc A. Viredaz, 1998
++ * DEC Western Research Laboratory, Palo Alto, CA
++ * Date April 1998 (April 1997)
++ * System Advanced RISC Machine (ARM)
++ * Language C or ARM Assembly
++ * Purpose Definition of macros to operate on bit fields.
++ */
++
++
++
++#ifndef __BITFIELD_H
++#define __BITFIELD_H
++
++#ifndef __ASSEMBLY__
++#define UData(Data) ((unsigned long) (Data))
++#else
++#define UData(Data) (Data)
++#endif
++
++
++/*
++ * MACRO: Fld
++ *
++ * Purpose
++ * The macro "Fld" encodes a bit field, given its size and its shift value
++ * with respect to bit 0.
++ *
++ * Note
++ * A more intuitive way to encode bit fields would have been to use their
++ * mask. However, extracting size and shift value information from a bit
++ * field's mask is cumbersome and might break the assembler (255-character
++ * line-size limit).
++ *
++ * Input
++ * Size Size of the bit field, in number of bits.
++ * Shft Shift value of the bit field with respect to bit 0.
++ *
++ * Output
++ * Fld Encoded bit field.
++ */
++
++#define Fld(Size, Shft) (((Size) << 16) + (Shft))
++
++
++/*
++ * MACROS: FSize, FShft, FMsk, FAlnMsk, F1stBit
++ *
++ * Purpose
++ * The macros "FSize", "FShft", "FMsk", "FAlnMsk", and "F1stBit" return
++ * the size, shift value, mask, aligned mask, and first bit of a
++ * bit field.
++ *
++ * Input
++ * Field Encoded bit field (using the macro "Fld").
++ *
++ * Output
++ * FSize Size of the bit field, in number of bits.
++ * FShft Shift value of the bit field with respect to bit 0.
++ * FMsk Mask for the bit field.
++ * FAlnMsk Mask for the bit field, aligned on bit 0.
++ * F1stBit First bit of the bit field.
++ */
++
++#define FSize(Field) ((Field) >> 16)
++#define FShft(Field) ((Field) & 0x0000FFFF)
++#define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field))
++#define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1)
++#define F1stBit(Field) (UData (1) << FShft (Field))
++
++
++/*
++ * MACRO: FInsrt
++ *
++ * Purpose
++ * The macro "FInsrt" inserts a value into a bit field by shifting the
++ * former appropriately.
++ *
++ * Input
++ * Value Bit-field value.
++ * Field Encoded bit field (using the macro "Fld").
++ *
++ * Output
++ * FInsrt Bit-field value positioned appropriately.
++ */
++
++#define FInsrt(Value, Field) \
++ (UData (Value) << FShft (Field))
++
++
++/*
++ * MACRO: FExtr
++ *
++ * Purpose
++ * The macro "FExtr" extracts the value of a bit field by masking and
++ * shifting it appropriately.
++ *
++ * Input
++ * Data Data containing the bit-field to be extracted.
++ * Field Encoded bit field (using the macro "Fld").
++ *
++ * Output
++ * FExtr Bit-field value.
++ */
++
++#define FExtr(Data, Field) \
++ ((UData (Data) >> FShft (Field)) & FAlnMsk (Field))
++
++
++#endif /* __BITFIELD_H */
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/cerf.h
+@@ -0,0 +1,177 @@
++/*
++ * linux/include/asm-arm/arch-pxa/cerf.h
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * Add CerfBoard Specifics here...
++ */
++
++/*
++ * Memory sizes
++ */
++
++#define CERF_RAM_BASE 0xa0000000
++
++#ifdef CONFIG_PXA_CERF_RAM_128MB
++#define CERF_RAM_SIZE 128*1024*1024
++
++#elif defined (CONFIG_PXA_CERF_RAM_64MB)
++#define CERF_RAM_SIZE 64*1024*1024
++
++#elif defined (CONFIG_PXA_CERF_RAM_32MB)
++#define CERF_RAM_SIZE 32*1024*1024
++
++#elif defined (CONFIG_PXA_CERF_RAM_16MB)
++#define CERF_RAM_SIZE 16*1024*1024
++#endif
++
++/*
++ * CS memory timing via Static Memory Control Register (MSC0-2)
++ */
++
++#define MSC_CS(cs,val) ((val)<<((cs&1)<<4))
++
++#define MSC_RBUFF_SHIFT 15
++#define MSC_RBUFF_SLOW (0)
++#define MSC_RBUFF_FAST (1)
++#define MSC_RBUFF(x) ((x)<<MSC_RBUFF_SHIFT)
++
++#define MSC_RRR_SHIFT 12
++#define MSC_RRR(x) ((x)<<MSC_RRR_SHIFT)
++
++#define MSC_RDN_SHIFT 8
++#define MSC_RDN(x) ((x)<<MSC_RDN_SHIFT)
++
++#define MSC_RDF_SHIFT 4
++#define MSC_RDF(x) ((x)<<MSC_RDF_SHIFT)
++
++#define MSC_RBW_SHIFT 3
++#define MSC_RBW(x) ((x)<<MSC_RBW_SHIFT)
++
++#define MSC_RT_SHIFT 0
++#define MSC_RT(x) ((x)<<MSC_RT_SHIFT)
++
++/*
++ * IO Pins for devices
++ */
++
++#define CERF_FLASH_BASE 0xe8000000
++#define CERF_FLASH_SIZE 0x02000000
++#define CERF_FLASH_PHYS PXA_CS0_PHYS
++
++#define CERF_ETH_BASE 0xf0000000
++#define CERF_ETH_SIZE 0x00100000
++#define CERF_ETH_PHYS PXA_CS1_PHYS
++
++#define CERF_BT_BASE 0xf2000000
++#define CERF_BT_SIZE 0x00100000
++#define CERF_BT_PHYS PXA_CS2_PHYS
++
++#define CERF_SERIAL_BASE 0xf3000000
++#define CERF_SERIAL_SIZE 0x00100000
++#define CERF_SERIAL_PHYS PXA_CS3_PHYS
++
++#define CERF_CPLD_BASE 0xf1000000
++#define CERF_CPLD_SIZE 0x00100000
++#define CERF_CPLD_PHYS PXA_CS4_PHYS
++
++#define CERF_PDA_CPLD_WRCLRINT (0x0)
++#define CERF_PDA_CPLD_BRIGHTNESS (0x2)
++#define CERF_PDA_CPLD_KEYPAD_A (0x6)
++#define CERF_PDA_CPLD_BATTFAULT (0x8)
++#define CERF_PDA_CPLD_KEYPAD_B (0xa)
++#define CERF_PDA_CPLD_SOUND_ENA (0xc)
++
++#define CERF_PDA_SOUND_ENABLE 0x1
++#define CERF_PDA_DEFAULT_BRIGHTNESS 0x9
++
++/*
++ * Access functions (registers are 4-bit wide)
++ */
++
++#define CERF_PDA_CPLD CERF_CPLD_BASE
++
++#define CERF_PDA_CPLD_Get(x, y) (*((char*)(CERF_PDA_CPLD + (x))) & (y))
++#define CERF_PDA_CPLD_Set(x, y, z) (*((char*)(CERF_PDA_CPLD + (x))) = (*((char*)(CERF_PDA_CPLD + (x))) & ~(z)) | (y))
++#define CERF_PDA_CPLD_UnSet(x, y, z) (*((char*)(CERF_PDA_CPLD + (x))) = (*((char*)(CERF_PDA_CPLD + (x))) & ~(z)) & ~(y))
++
++/*
++ * IO and IRQ settings for cs8900 ethernet chip
++ */
++#define CERF_ETH_IO CERF_ETH_BASE
++#define CERF_ETH_IRQ GPIO_2_80_TO_IRQ(21)
++
++/*
++ * We only have one LED on the XScale CerfPDA so only the
++ * time or idle should ever be selected.
++ */
++#define CERF_HEARTBEAT_LED 0x1
++#define CERF_SYS_BUSY_LED 0x2
++
++#define CERF_HEARTBEAT_LED_GPIO 16 // GPIO 4
++#define CERF_SYS_BUSY_LED_GPIO 16 // GPIO 4
++
++#define CERF_HEARTBEAT_LED_ON (GPSR0 = CERF_HEARTBEAT_LED_GPIO)
++#define CERF_HEARTBEAT_LED_OFF (GPCR0 = CERF_HEARTBEAT_LED_GPIO)
++#define CERF_SYS_BUSY_LED_ON (GPSR0 = CERF_SYS_BUSY_LED_GPIO)
++#define CERF_SYS_BUSY_LED_OFF (GPCR0 = CERF_SYS_BUSY_LED_GPIO)
++
++/*
++ * UCB 1400 gpio
++ */
++
++#define CERF_GPIO_UCB1400_IRQ 32
++
++#define UCB_IO_0 (1 << 0)
++#define UCB_IO_1 (1 << 1)
++#define UCB_IO_2 (1 << 2)
++#define UCB_IO_3 (1 << 3)
++#define UCB_IO_4 (1 << 4)
++#define UCB_IO_5 (1 << 5)
++#define UCB_IO_6 (1 << 6)
++#define UCB_IO_7 (1 << 7)
++#define UCB_IO_8 (1 << 8)
++#define UCB_IO_9 (1 << 9)
++
++#define UCB1400_GPIO_CONT_CS UCB_IO_0
++#define UCB1400_GPIO_CONT_DOWN UCB_IO_1
++#define UCB1400_GPIO_CONT_INC UCB_IO_2
++#define UCB1400_GPIO_CONT_ENA UCB_IO_3
++#define UCB1400_GPIO_LCD_RESET UCB_IO_4
++#define UCB1400_GPIO_IRDA_ENABLE UCB_IO_5
++#define UCB1400_GPIO_BT_ENABLE UCB_IO_6
++#define UCB1400_GPIO_TEST_P1 UCB_IO_7
++#define UCB1400_GPIO_TEST_P2 UCB_IO_8
++#define UCB1400_GPIO_TEST_P3 UCB_IO_9
++
++/*
++ * IRQ for devices
++ */
++#define UCB1400_IRQ(x) (NR_IRQS + 1 + (x))
++
++#define IRQ_UCB1400_IO0 UCB1400_IRQ(0)
++#define IRQ_UCB1400_IO1 UCB1400_IRQ(1)
++#define IRQ_UCB1400_IO2 UCB1400_IRQ(2)
++#define IRQ_UCB1400_IO3 UCB1400_IRQ(3)
++#define IRQ_UCB1400_IO4 UCB1400_IRQ(4)
++#define IRQ_UCB1400_IO5 UCB1400_IRQ(5)
++#define IRQ_UCB1400_IO6 UCB1400_IRQ(6)
++#define IRQ_UCB1400_IO7 UCB1400_IRQ(7)
++#define IRQ_UCB1400_IO8 UCB1400_IRQ(8)
++#define IRQ_UCB1400_IO9 UCB1400_IRQ(9)
++
++#define IRQ_UCB1400_CONT_CS IRQ_UCB1400_IO0
++#define IRQ_UCB1400_CONT_DOWN IRQ_UCB1400_IO1
++#define IRQ_UCB1400_CONT_INC IRQ_UCB1400_IO2
++#define IRQ_UCB1400_CONT_ENA IRQ_UCB1400_IO3
++#define IRQ_UCB1400_LCD_RESET IRQ_UCB1400_IO4
++#define IRQ_UCB1400_IRDA_ENABLE IRQ_UCB1400_IO5
++#define IRQ_UCB1400_BT_ENABLE IRQ_UCB1400_IO6
++#define IRQ_UCB1400_TEST_P1 IRQ_UCB1400_IO7
++#define IRQ_UCB1400_TEST_P2 IRQ_UCB1400_IO8
++#define IRQ_UCB1400_TEST_P3 IRQ_UCB1400_IO9
++
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/cerf_ucb1400gpio.h
+@@ -0,0 +1,30 @@
++/*
++ * cerf_ucb1400gpio.h
++ *
++ * UCB1400 GPIO control stuff for the cerf.
++ *
++ * Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * History:
++ * Mar 2002: Initial version [FB]
++ *
++ */
++/* -- lcd -- */
++extern void cerf_ucb1400gpio_lcd_enable( void);
++extern void cerf_ucb1400gpio_lcd_disable( void);
++extern void cerf_ucb1400gpio_lcd_contrast_step( int direction);
++
++/* -- irda -- */
++extern void cerf_ucb1400gpio_irda_enable( void);
++extern void cerf_ucb1400gpio_irda_disable( void);
++
++/* -- bt -- */
++extern void cerf_ucb1400gpio_bt_enable( void);
++extern void cerf_ucb1400gpio_bt_disable( void);
++
++/* -- init -- */
++extern int cerf_ucb1400gpio_init(void);
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/csb226.h
+@@ -0,0 +1,99 @@
++/*
++ * linux/include/asm-arm/arch-pxa/csb226.h
++ *
++ * Author: Robert Schwebel (stolen from lubbock.h)
++ * Created: Oct 30, 2002
++ * Copyright: Pengutronix
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#define CSB226_FPGA_PHYS PXA_CS2_PHYS
++
++#define CSB226_FPGA_VIRT (0xf0000000) /* phys 0x08000000 */
++#define CSB226_ETH_BASE (0xf1000000) /* phys 0x0c000000 */
++
++#define CSB226_P2V(x) ((x) - CSB226_FPGA_PHYS + CSB226_FPGA_VIRT)
++#define CSB226_V2P(x) ((x) - CSB226_FPGA_VIRT + CSB226_FPGA_PHYS)
++
++#ifndef __ASSEMBLY__
++# define __CSB226_REG(x) (*((volatile unsigned long *)CSB226_P2V(x)))
++#else
++# define __CSB226_REG(x) CSB226_P2V(x)
++#endif
++
++
++/* register physical addresses */
++#define _CSB226_MISC_WR (CSB226_FPGA_PHYS + 0x080)
++#define _CSB226_MISC_RD (CSB226_FPGA_PHYS + 0x090)
++#define _CSB226_IRQ_MASK_EN (CSB226_FPGA_PHYS + 0x0C0)
++#define _CSB226_IRQ_SET_CLR (CSB226_FPGA_PHYS + 0x0D0)
++#define _CSB226_GP (CSB226_FPGA_PHYS + 0x100)
++
++
++
++/* register virtual addresses */
++
++#define CSB226_MISC_WR __CSB226_REG(_CSB226_MISC_WR)
++#define CSB226_MISC_RD __CSB226_REG(_CSB226_MISC_RD)
++#define CSB226_IRQ_MASK_EN __CSB226_REG(_CSB226_IRQ_MASK_EN)
++#define CSB226_IRQ_SET_CLR __CSB226_REG(_CSB226_IRQ_SET_CLR)
++#define CSB226_GP __CSB226_REG(_CSB226_GP)
++
++
++/* GPIOs */
++
++#define GPIO_CSB226_IRQ 0
++#define IRQ_GPIO_CSB226_IRQ IRQ_GPIO0
++
++
++/*
++ * LED macros
++ */
++
++// #define LEDS_BASE LUB_DISC_BLNK_LED
++
++// 8 discrete leds available for general use:
++
++/*
++#define D28 0x1
++#define D27 0x2
++#define D26 0x4
++#define D25 0x8
++#define D24 0x10
++#define D23 0x20
++#define D22 0x40
++#define D21 0x80
++*/
++
++/* Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays so
++* be sure to not monkey with them here.
++*/
++
++/*
++#define HEARTBEAT_LED D28
++#define SYS_BUSY_LED D27
++#define HEXLEDS_BASE LUB_HEXLED
++
++#define HEARTBEAT_LED_ON (LEDS_BASE &= ~HEARTBEAT_LED)
++#define HEARTBEAT_LED_OFF (LEDS_BASE |= HEARTBEAT_LED)
++#define SYS_BUSY_LED_OFF (LEDS_BASE |= SYS_BUSY_LED)
++#define SYS_BUSY_LED_ON (LEDS_BASE &= ~SYS_BUSY_LED)
++
++// use x = D26-D21 for these, please...
++#define DISCRETE_LED_ON(x) (LEDS_BASE &= ~(x))
++#define DISCRETE_LED_OFF(x) (LEDS_BASE |= (x))
++*/
++
++#ifndef __ASSEMBLY__
++
++//extern int hexled_val = 0;
++
++#endif
++
++/*
++#define BUMP_COUNTER (HEXLEDS_BASE = hexled_val++)
++#define DEC_COUNTER (HEXLEDS_BASE = hexled_val--)
++*/
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/dma.h
+@@ -0,0 +1,49 @@
++/*
++ * linux/include/asm-arm/arch-pxa/dma.h
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef __ASM_ARCH_DMA_H
++#define __ASM_ARCH_DMA_H
++
++#define MAX_DMA_ADDRESS 0xffffffff
++
++/* No DMA as the rest of the world see it */
++#define MAX_DMA_CHANNELS 0
++
++/*
++ * Descriptor structure for PXA's DMA engine
++ * Note: this structure must always be aligned to a 16-byte boundary.
++ */
++
++typedef struct {
++ volatile u32 ddadr; /* Points to the next descriptor + flags */
++ volatile u32 dsadr; /* DSADR value for the current transfer */
++ volatile u32 dtadr; /* DTADR value for the current transfer */
++ volatile u32 dcmd; /* DCMD value for the current transfer */
++} pxa_dma_desc;
++
++/*
++ * DMA registration
++ */
++
++typedef enum {
++ DMA_PRIO_HIGH = 0,
++ DMA_PRIO_MEDIUM = 4,
++ DMA_PRIO_LOW = 8
++} pxa_dma_prio;
++
++int pxa_request_dma (char *name,
++ pxa_dma_prio prio,
++ void (*irq_handler)(int, void *, struct pt_regs *),
++ void *data);
++
++void pxa_free_dma (int dma_ch);
++
++#endif /* _ASM_ARCH_DMA_H */
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/hardware.h
+@@ -0,0 +1,142 @@
++/*
++ * linux/include/asm-arm/arch-pxa/hardware.h
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef __ASM_ARCH_HARDWARE_H
++#define __ASM_ARCH_HARDWARE_H
++
++#include <linux/config.h>
++#include <asm/mach-types.h>
++
++
++/*
++ * These are statically mapped PCMCIA IO space for designs using it as a
++ * generic IO bus, typically with ISA parts, hardwired IDE interfaces, etc.
++ * The actual PCMCIA code is mapping required IO region at run time.
++ */
++#define PCMCIA_IO_0_BASE 0xf6000000
++#define PCMCIA_IO_1_BASE 0xf7000000
++
++
++/*
++ * XIP kernel text mapping.
++ * Note: the exact virtual address is also specified in arch/arm/Makefile.
++ */
++#ifdef CONFIG_XIP_KERNEL
++#define KERNEL_XIP_BASE_PHYS (CONFIG_XIP_PHYS_ADDR & 0xffe00000)
++#define KERNEL_XIP_BASE_VIRT 0xe8000000
++#endif
++
++
++/*
++ * We requires absolute addresses.
++ */
++#define PCIO_BASE 0
++
++/*
++ * Workarounds for at least 2 errata so far require this.
++ * The mapping is set in mach-pxa/generic.c.
++ */
++#define UNCACHED_PHYS_0 0xff000000
++#define UNCACHED_ADDR UNCACHED_PHYS_0
++
++/*
++ * Intel PXA internal I/O mappings:
++ *
++ * 0x40000000 - 0x41ffffff <--> 0xf8000000 - 0xf9ffffff
++ * 0x44000000 - 0x45ffffff <--> 0xfa000000 - 0xfbffffff
++ * 0x48000000 - 0x49ffffff <--> 0xfc000000 - 0xfdffffff
++ */
++
++#define io_p2v(x) ( ((x) | 0xbe000000) ^ (~((x) >> 1) & 0x06000000) )
++#define io_v2p( x ) ( ((x) & 0x41ffffff) ^ ( ((x) & 0x06000000) << 1) )
++
++#ifndef __ASSEMBLY__
++
++#if 0
++# define __REG(x) (*((volatile u32 *)io_p2v(x)))
++#else
++/*
++ * This __REG() version gives the same results as the one above, except
++ * that we are fooling gcc somehow so it generates far better and smaller
++ * assembly code for access to contigous registers. It's a shame that gcc
++ * doesn't guess this by itself.
++ */
++#include <asm/types.h>
++typedef struct { volatile u32 offset[4096]; } __regbase;
++# define __REGP(x) ((__regbase *)((x)&~4095))->offset[((x)&4095)>>2]
++# define __REG(x) __REGP(io_p2v(x))
++#endif
++
++/* Let's kick gcc's ass again... */
++# define __REG2(x,y) \
++ ( __builtin_constant_p(y) ? (__REG((x) + (y))) \
++ : (*(volatile u32 *)((u32)&__REG(x) + (y))) )
++
++# define __PREG(x) (io_v2p((u32)&(x)))
++
++#else
++
++# define __REG(x) io_p2v(x)
++# define __PREG(x) io_v2p(x)
++
++#endif
++
++#include "pxa-regs.h"
++
++#ifndef __ASSEMBLY__
++
++/*
++ * GPIO edge detection for IRQs:
++ * IRQs are generated on Falling-Edge, Rising-Edge, or both.
++ * This must be called *before* the corresponding IRQ is registered.
++ * Use this instead of directly setting GRER/GFER.
++ */
++#define GPIO_FALLING_EDGE 1
++#define GPIO_RISING_EDGE 2
++#define GPIO_BOTH_EDGES 3
++extern void set_GPIO_IRQ_edge( int gpio_nr, int edge_mask );
++
++/*
++ * Handy routine to set GPIO alternate functions
++ */
++extern void set_GPIO_mode( int gpio_mode );
++
++/*
++ * return current lclk frequency in units of 10kHz
++ */
++extern unsigned int get_lclk_frequency_10khz(void);
++
++/*
++ * return current clk frequency in units of 1kHz
++ */
++extern unsigned int get_clk_frequency_khz( int info);
++
++#endif
++
++
++/*
++ * Implementation specifics
++ */
++
++//#ifdef CONFIG_ARCH_LUBBOCK
++#include "lubbock.h"
++//#endif
++
++//#ifdef CONFIG_ARCH_PXA_IDP
++#include "idp.h"
++//#endif
++
++//#ifdef CONFIG_ARCH_PXA_CERF
++#include "cerf.h"
++//#endif
++
++#endif /* _ASM_ARCH_HARDWARE_H */
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/ide.h
+@@ -0,0 +1,59 @@
++/*
++ * linux/include/asm-arm/arch-pxa/ide.h
++ *
++ * Author: George Davis
++ * Created: Jan 10, 2002
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *
++ * Originally based upon linux/include/asm-arm/arch-sa1100/ide.h
++ *
++ */
++
++#include <linux/config.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++
++
++/*
++ * Set up a hw structure for a specified data port, control port and IRQ.
++ * This should follow whatever the default interface uses.
++ */
++static __inline__ void
++ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
++{
++ ide_ioreg_t reg;
++
++ memset(hw, 0, sizeof(*hw));
++
++ reg = (ide_ioreg_t)data_port;
++
++ hw->io_ports[IDE_DATA_OFFSET] = reg + 0;
++ hw->io_ports[IDE_ERROR_OFFSET] = reg + 1;
++ hw->io_ports[IDE_NSECTOR_OFFSET] = reg + 2;
++ hw->io_ports[IDE_SECTOR_OFFSET] = reg + 3;
++ hw->io_ports[IDE_LCYL_OFFSET] = reg + 4;
++ hw->io_ports[IDE_HCYL_OFFSET] = reg + 5;
++ hw->io_ports[IDE_SELECT_OFFSET] = reg + 6;
++ hw->io_ports[IDE_STATUS_OFFSET] = reg + 7;
++
++ hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
++
++ if (irq)
++ *irq = 0;
++}
++
++
++/*
++ * Register the standard ports for this architecture with the IDE driver.
++ */
++static __inline__ void
++ide_init_default_hwifs(void)
++{
++ /* Nothing to declare... */
++}
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/idp.h
+@@ -0,0 +1,468 @@
++/*
++ * linux/include/asm-arm/arch-pxa/idp.h
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Copyright (c) 2001 Cliff Brake, Accelent Systems Inc.
++ *
++ * 2001-09-13: Cliff Brake <cbrake@accelent.com>
++ * Initial code
++ *
++ */
++
++
++/*
++ * Note: this file must be safe to include in assembly files
++ */
++
++/* comment out following if you have a rev01 board */
++#define PXA_IDP_REV02 1
++//#undef PXA_IDP_REV02
++
++#ifdef PXA_IDP_REV02
++
++//Use this as well for 0017-x004 and greater pcb's:
++#define PXA_IDP_REV04 1
++
++#define IDP_FLASH_PHYS (PXA_CS0_PHYS)
++#define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS)
++#define IDP_MEDIAQ_PHYS (PXA_CS3_PHYS)
++#define IDP_IDE_PHYS (PXA_CS5_PHYS + 0x03000000)
++#define IDP_ETH_PHYS (PXA_CS5_PHYS + 0x03400000)
++#define IDP_COREVOLT_PHYS (PXA_CS5_PHYS + 0x03800000)
++#define IDP_CPLD_PHYS (PXA_CS5_PHYS + 0x03C00000)
++
++
++/*
++ * virtual memory map
++ */
++
++#define IDP_IDE_BASE (0xf0000000)
++#define IDP_IDE_SIZE (1*1024*1024)
++
++#define IDP_ETH_BASE (IDP_IDE_BASE + IDP_IDE_SIZE)
++#define IDP_ETH_SIZE (1*1024*1024)
++#define ETH_BASE IDP_ETH_BASE //smc9194 driver compatibility issue
++
++#define IDP_COREVOLT_BASE (IDP_ETH_BASE + IDP_ETH_SIZE)
++#define IDP_COREVOLT_SIZE (1*1024*1024)
++
++#define IDP_CPLD_BASE (IDP_COREVOLT_BASE + IDP_COREVOLT_SIZE)
++#define IDP_CPLD_SIZE (1*1024*1024)
++
++#if (IDP_CPLD_BASE + IDP_CPLD_SIZE) > 0xfc000000
++#error Your custom IO space is getting a bit large !!
++#endif
++
++#define CPLD_P2V(x) ((x) - IDP_CPLD_PHYS + IDP_CPLD_BASE)
++#define CPLD_V2P(x) ((x) - IDP_CPLD_BASE + IDP_CPLD_PHYS)
++
++#ifndef __ASSEMBLY__
++# define __CPLD_REG(x) (*((volatile unsigned long *)CPLD_P2V(x)))
++#else
++# define __CPLD_REG(x) CPLD_P2V(x)
++#endif
++
++/* board level registers in the CPLD: (offsets from CPLD_BASE) */
++
++#define _IDP_CPLD_REV (IDP_CPLD_PHYS + 0x00)
++#define _IDP_CPLD_PERIPH_PWR (IDP_CPLD_PHYS + 0x04)
++#define _IDP_CPLD_LED_CONTROL (IDP_CPLD_PHYS + 0x08)
++#define _IDP_CPLD_KB_COL_HIGH (IDP_CPLD_PHYS + 0x0C)
++#define _IDP_CPLD_KB_COL_LOW (IDP_CPLD_PHYS + 0x10)
++#define _IDP_CPLD_PCCARD_EN (IDP_CPLD_PHYS + 0x14)
++#define _IDP_CPLD_GPIOH_DIR (IDP_CPLD_PHYS + 0x18)
++#define _IDP_CPLD_GPIOH_VALUE (IDP_CPLD_PHYS + 0x1C)
++#define _IDP_CPLD_GPIOL_DIR (IDP_CPLD_PHYS + 0x20)
++#define _IDP_CPLD_GPIOL_VALUE (IDP_CPLD_PHYS + 0x24)
++#define _IDP_CPLD_PCCARD_PWR (IDP_CPLD_PHYS + 0x28)
++#define _IDP_CPLD_MISC_CTRL (IDP_CPLD_PHYS + 0x2C)
++#define _IDP_CPLD_LCD (IDP_CPLD_PHYS + 0x30)
++#define _IDP_CPLD_FLASH_WE (IDP_CPLD_PHYS + 0x34)
++
++#define _IDP_CPLD_KB_ROW (IDP_CPLD_PHYS + 0x50)
++#define _IDP_CPLD_PCCARD0_STATUS (IDP_CPLD_PHYS + 0x54)
++#define _IDP_CPLD_PCCARD1_STATUS (IDP_CPLD_PHYS + 0x58)
++#define _IDP_CPLD_MISC_STATUS (IDP_CPLD_PHYS + 0x5C)
++
++/* FPGA register virtual addresses */
++
++#define IDP_CPLD_REV __CPLD_REG(_IDP_CPLD_REV)
++#define IDP_CPLD_PERIPH_PWR __CPLD_REG(_IDP_CPLD_PERIPH_PWR)
++#define IDP_CPLD_LED_CONTROL __CPLD_REG(_IDP_CPLD_LED_CONTROL)
++#define IDP_CPLD_KB_COL_HIGH __CPLD_REG(_IDP_CPLD_KB_COL_HIGH)
++#define IDP_CPLD_KB_COL_LOW __CPLD_REG(_IDP_CPLD_KB_COL_LOW)
++#define IDP_CPLD_PCCARD_EN __CPLD_REG(_IDP_CPLD_PCCARD_EN)
++#define IDP_CPLD_GPIOH_DIR __CPLD_REG(_IDP_CPLD_GPIOH_DIR)
++#define IDP_CPLD_GPIOH_VALUE __CPLD_REG(_IDP_CPLD_GPIOH_VALUE)
++#define IDP_CPLD_GPIOL_DIR __CPLD_REG(_IDP_CPLD_GPIOL_DIR)
++#define IDP_CPLD_GPIOL_VALUE __CPLD_REG(_IDP_CPLD_GPIOL_VALUE)
++#define IDP_CPLD_PCCARD_PWR __CPLD_REG(_IDP_CPLD_PCCARD_PWR)
++#define IDP_CPLD_MISC_CTRL __CPLD_REG(_IDP_CPLD_MISC_CTRL)
++#define IDP_CPLD_LCD __CPLD_REG(_IDP_CPLD_LCD)
++#define IDP_CPLD_FLASH_WE __CPLD_REG(_IDP_CPLD_FLASH_WE)
++
++#define IDP_CPLD_KB_ROW __CPLD_REG(_IDP_CPLD_KB_ROW)
++#define IDP_CPLD_PCCARD0_STATUS __CPLD_REG(_IDP_CPLD_PCCARD0_STATUS)
++#define IDP_CPLD_PCCARD1_STATUS __CPLD_REG(_IDP_CPLD_PCCARD1_STATUS)
++#define IDP_CPLD_MISC_STATUS __CPLD_REG(_IDP_CPLD_MISC_STATUS)
++
++
++/*
++ * Bit masks for various registers
++ */
++// IDP_CPLD_PCCARD_PWR
++#define PCC0_PWR0 (1 << 0)
++#define PCC0_PWR1 (1 << 1)
++#define PCC0_PWR2 (1 << 2)
++#define PCC0_PWR3 (1 << 3)
++#define PCC1_PWR0 (1 << 4)
++#define PCC1_PWR1 (1 << 5)
++#define PCC1_PWR2 (1 << 6)
++#define PCC1_PWR3 (1 << 7)
++
++// IDP_CPLD_PCCARD_EN
++#define PCC0_RESET (1 << 6)
++#define PCC1_RESET (1 << 7)
++#define PCC0_ENABLE (1 << 0)
++#define PCC1_ENABLE (1 << 1)
++
++// IDP_CPLD_PCCARDx_STATUS
++#define _PCC_WRPROT (1 << 7) // 7-4 read as low true
++#define _PCC_RESET (1 << 6)
++#define _PCC_IRQ (1 << 5)
++#define _PCC_INPACK (1 << 4)
++#define PCC_BVD2 (1 << 3)
++#define PCC_BVD1 (1 << 2)
++#define PCC_VS2 (1 << 1)
++#define PCC_VS1 (1 << 0)
++
++#define PCC_DETECT(x) (GPLR(7 + (x)) & GPIO_bit(7 + (x)))
++
++/*
++ * Macros for LCD Driver
++ */
++
++#ifdef CONFIG_FB_PXA
++
++#define FB_BACKLIGHT_ON() (IDP_CPLD_LCD |= (1<<1))
++#define FB_BACKLIGHT_OFF() (IDP_CPLD_LCD &= ~(1<<1))
++
++#define FB_PWR_ON() (IDP_CPLD_LCD |= (1<< 0))
++#define FB_PWR_OFF() (IDP_CPLD_LCD &= ~(1<<0))
++
++#define FB_VLCD_ON() (IDP_CPLD_LCD |= (1<<2))
++#define FB_VLCD_OFF() (IDP_CPLD_LCD &= ~(1<<2))
++
++#endif
++
++/* A listing of interrupts used by external hardware devices */
++
++#ifdef PXA_IDP_REV04
++#define TOUCH_PANEL_IRQ IRQ_GPIO(5)
++#define IDE_IRQ IRQ_GPIO(21)
++#else
++#define TOUCH_PANEL_IRQ IRQ_GPIO(21)
++#define IDE_IRQ IRQ_GPIO(5)
++#endif
++
++#define TOUCH_PANEL_IRQ_EDGE GPIO_FALLING_EDGE
++
++#define IDE_IRQ_EDGE GPIO_RISING_EDGE
++
++#define ETHERNET_IRQ IRQ_GPIO(4)
++#define ETHERNET_IRQ_EDGE GPIO_RISING_EDGE
++
++#define IDE_IRQ_EDGE GPIO_RISING_EDGE
++
++#define PCMCIA_S0_CD_VALID IRQ_GPIO(7)
++#define PCMCIA_S0_CD_VALID_EDGE GPIO_BOTH_EDGES
++
++#define PCMCIA_S1_CD_VALID IRQ_GPIO(8)
++#define PCMCIA_S1_CD_VALID_EDGE GPIO_BOTH_EDGES
++
++#define PCMCIA_S0_RDYINT IRQ_GPIO(19)
++#define PCMCIA_S1_RDYINT IRQ_GPIO(22)
++
++/*
++ * Macros for LED Driver
++ */
++
++/* leds 0 = ON */
++#define IDP_HB_LED (1<<5)
++#define IDP_BUSY_LED (1<<6)
++
++#define IDP_LEDS_MASK (IDP_HB_LED | IDP_BUSY_LED)
++
++#define IDP_WRITE_LEDS(value) (IDP_CPLD_LED_CONTROL = (IDP_CPLD_LED_CONTROL & (~(IDP_LEDS_MASK)) | value))
++
++/*
++ * macros for MTD driver
++ */
++
++#define FLASH_WRITE_PROTECT_DISABLE() ((IDP_CPLD_FLASH_WE) &= ~(0x1))
++#define FLASH_WRITE_PROTECT_ENABLE() ((IDP_CPLD_FLASH_WE) |= (0x1))
++
++/*
++ * macros for matrix keyboard driver
++ */
++
++#define KEYBD_MATRIX_NUMBER_INPUTS 7
++#define KEYBD_MATRIX_NUMBER_OUTPUTS 14
++
++#define KEYBD_MATRIX_INVERT_OUTPUT_LOGIC FALSE
++#define KEYBD_MATRIX_INVERT_INPUT_LOGIC FALSE
++
++#define KEYBD_MATRIX_SETTLING_TIME_US 100
++#define KEYBD_MATRIX_KEYSTATE_DEBOUNCE_CONSTANT 2
++
++#define KEYBD_MATRIX_SET_OUTPUTS(outputs) \
++{\
++ IDP_CPLD_KB_COL_LOW = outputs;\
++ IDP_CPLD_KB_COL_HIGH = outputs >> 7;\
++}
++
++#define KEYBD_MATRIX_GET_INPUTS(inputs) \
++{\
++ inputs = (IDP_CPLD_KB_ROW & 0x7f);\
++}
++
++//------------------------------------------------------------------------------
++
++#else // must be rev 01
++
++/* -----------------------------------------------------------------------------
++ * following is for rev01 boards only
++ */
++
++#define IDP_FLASH_PHYS (PXA_CS0_PHYS)
++#define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS)
++#define IDP_MEDIAQ_PHYS (PXA_CS3_PHYS)
++#define IDP_CTRL_PORT_PHYS (PXA_CS5_PHYS + 0x02C00000)
++#define IDP_IDE_PHYS (PXA_CS5_PHYS + 0x03000000)
++#define IDP_ETH_PHYS (PXA_CS5_PHYS + 0x03400000)
++#define IDP_COREVOLT_PHYS (PXA_CS5_PHYS + 0x03800000)
++#define IDP_CPLD_PHYS (PXA_CS5_PHYS + 0x03C00000)
++
++
++/*
++ * virtual memory map
++ */
++
++#define IDP_CTRL_PORT_BASE (0xf0000000)
++#define IDP_CTRL_PORT_SIZE (1*1024*1024)
++
++#define IDP_IDE_BASE (IDP_CTRL_PORT_BASE + IDP_CTRL_PORT_SIZE)
++#define IDP_IDE_SIZE (1*1024*1024)
++
++#define IDP_ETH_BASE (IDP_IDE_BASE + IDP_IDE_SIZE)
++#define IDP_ETH_SIZE (1*1024*1024)
++
++#define IDP_COREVOLT_BASE (IDP_ETH_BASE + IDP_ETH_SIZE)
++#define IDP_COREVOLT_SIZE (1*1024*1024)
++
++#define IDP_CPLD_BASE (IDP_COREVOLT_BASE + IDP_COREVOLT_SIZE)
++#define IDP_CPLD_SIZE (1*1024*1024)
++
++#if (IDP_CPLD_BASE + IDP_CPLD_SIZE) > 0xfc000000
++#error Your custom IO space is getting a bit large !!
++#endif
++
++#define CPLD_P2V(x) ((x) - IDP_CPLD_PHYS + IDP_CPLD_BASE)
++#define CPLD_V2P(x) ((x) - IDP_CPLD_BASE + IDP_CPLD_PHYS)
++
++#ifndef __ASSEMBLY__
++# define __CPLD_REG(x) (*((volatile unsigned long *)CPLD_P2V(x)))
++#else
++# define __CPLD_REG(x) CPLD_P2V(x)
++#endif
++
++/* board level registers in the CPLD: (offsets from CPLD_BASE) */
++
++#define _IDP_CPLD_LED_CONTROL (IDP_CPLD_PHYS + 0x00)
++#define _IDP_CPLD_PERIPH_PWR (IDP_CPLD_PHYS + 0x04)
++#define _IDP_CPLD_CIR (IDP_CPLD_PHYS + 0x08)
++#define _IDP_CPLD_KB_COL_HIGH (IDP_CPLD_PHYS + 0x0C)
++#define _IDP_CPLD_KB_COL_LOW (IDP_CPLD_PHYS + 0x10)
++#define _IDP_CPLD_PCCARD_EN (IDP_CPLD_PHYS + 0x14)
++#define _IDP_CPLD_GPIOH_DIR (IDP_CPLD_PHYS + 0x18)
++#define _IDP_CPLD_GPIOH_VALUE (IDP_CPLD_PHYS + 0x1C)
++#define _IDP_CPLD_GPIOL_DIR (IDP_CPLD_PHYS + 0x20)
++#define _IDP_CPLD_GPIOL_VALUE (IDP_CPLD_PHYS + 0x24)
++#define _IDP_CPLD_MISC (IDP_CPLD_PHYS + 0x28)
++#define _IDP_CPLD_PCCARD0_STATUS (IDP_CPLD_PHYS + 0x2C)
++#define _IDP_CPLD_PCCARD1_STATUS (IDP_CPLD_PHYS + 0x30)
++
++/* FPGA register virtual addresses */
++#define IDP_CPLD_LED_CONTROL __CPLD_REG(_IDP_CPLD_LED_CONTROL) /* write only */
++#define IDP_CPLD_PERIPH_PWR __CPLD_REG(_IDP_CPLD_PERIPH_PWR) /* write only */
++#define IDP_CPLD_CIR __CPLD_REG(_IDP_CPLD_CIR) /* write only */
++#define IDP_CPLD_KB_COL_HIGH __CPLD_REG(_IDP_CPLD_KB_COL_HIGH) /* write only */
++#define IDP_CPLD_KB_COL_LOW __CPLD_REG(_IDP_CPLD_KB_COL_LOW) /* write only */
++#define IDP_CPLD_PCCARD_EN __CPLD_REG(_IDP_CPLD_PCCARD_EN) /* write only */
++#define IDP_CPLD_GPIOH_DIR __CPLD_REG(_IDP_CPLD_GPIOH_DIR) /* write only */
++#define IDP_CPLD_GPIOH_VALUE __CPLD_REG(_IDP_CPLD_GPIOH_VALUE) /* write only */
++#define IDP_CPLD_GPIOL_DIR __CPLD_REG(_IDP_CPLD_GPIOL_DIR) /* write only */
++#define IDP_CPLD_GPIOL_VALUE __CPLD_REG(_IDP_CPLD_GPIOL_VALUE) /* write only */
++#define IDP_CPLD_MISC __CPLD_REG(_IDP_CPLD_MISC) /* read only */
++#define IDP_CPLD_PCCARD0_STATUS __CPLD_REG(_IDP_CPLD_PCCARD0_STATUS) /* read only */
++#define IDP_CPLD_PCCARD1_STATUS __CPLD_REG(_IDP_CPLD_PCCARD1_STATUS) /* read only */
++
++
++#ifndef __ASSEMBLY__
++
++/* shadow registers for write only registers */
++extern unsigned int idp_cpld_led_control_shadow;
++extern unsigned int idp_cpld_periph_pwr_shadow;
++extern unsigned int idp_cpld_cir_shadow;
++extern unsigned int idp_cpld_kb_col_high_shadow;
++extern unsigned int idp_cpld_kb_col_low_shadow;
++extern unsigned int idp_cpld_pccard_en_shadow;
++extern unsigned int idp_cpld_gpioh_dir_shadow;
++extern unsigned int idp_cpld_gpioh_value_shadow;
++extern unsigned int idp_cpld_gpiol_dir_shadow;
++extern unsigned int idp_cpld_gpiol_value_shadow;
++
++extern unsigned int idp_control_port_shadow;
++
++/*
++ * macros to write to write only register
++ *
++ * none of these macros are protected from
++ * multiple drivers using them in interrupt context.
++ */
++
++#define WRITE_IDP_CPLD_LED_CONTROL(value, mask) \
++{\
++ idp_cpld_led_control_shadow = ((value & mask) | (idp_cpld_led_control_shadow & ~mask));\
++ IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\
++}
++#define WRITE_IDP_CPLD_PERIPH_PWR(value, mask) \
++{\
++ idp_cpld_periph_pwr_shadow = ((value & mask) | (idp_cpld_periph_pwr_shadow & ~mask));\
++ IDP_CPLD_PERIPH_PWR = idp_cpld_periph_pwr_shadow;\
++}
++#define WRITE_IDP_CPLD_CIR(value, mask) \
++{\
++ idp_cpld_cir_shadow = ((value & mask) | (idp_cpld_cir_shadow & ~mask));\
++ IDP_CPLD_CIR = idp_cpld_cir_shadow;\
++}
++#define WRITE_IDP_CPLD_KB_COL_HIGH(value, mask) \
++{\
++ idp_cpld_kb_col_high_shadow = ((value & mask) | (idp_cpld_kb_col_high_shadow & ~mask));\
++ IDP_CPLD_KB_COL_HIGH = idp_cpld_kb_col_high_shadow;\
++}
++#define WRITE_IDP_CPLD_KB_COL_LOW(value, mask) \
++{\
++ idp_cpld_kb_col_low_shadow = ((value & mask) | (idp_cpld_kb_col_low_shadow & ~mask));\
++ IDP_CPLD_KB_COL_LOW = idp_cpld_kb_col_low_shadow;\
++}
++#define WRITE_IDP_CPLD_PCCARD_EN(value, mask) \
++{\
++ idp_cpld_ = ((value & mask) | (idp_cpld_led_control_shadow & ~mask));\
++ IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\
++}
++#define WRITE_IDP_CPLD_GPIOH_DIR(value, mask) \
++{\
++ idp_cpld_gpioh_dir_shadow = ((value & mask) | (idp_cpld_gpioh_dir_shadow & ~mask));\
++ IDP_CPLD_GPIOH_DIR = idp_cpld_gpioh_dir_shadow;\
++}
++#define WRITE_IDP_CPLD_GPIOH_VALUE(value, mask) \
++{\
++ idp_cpld_gpioh_value_shadow = ((value & mask) | (idp_cpld_gpioh_value_shadow & ~mask));\
++ IDP_CPLD_GPIOH_VALUE = idp_cpld_gpioh_value_shadow;\
++}
++#define WRITE_IDP_CPLD_GPIOL_DIR(value, mask) \
++{\
++ idp_cpld_gpiol_dir_shadow = ((value & mask) | (idp_cpld_gpiol_dir_shadow & ~mask));\
++ IDP_CPLD_GPIOL_DIR = idp_cpld_gpiol_dir_shadow;\
++}
++#define WRITE_IDP_CPLD_GPIOL_VALUE(value, mask) \
++{\
++ idp_cpld_gpiol_value_shadow = ((value & mask) | (idp_cpld_gpiol_value_shadow & ~mask));\
++ IDP_CPLD_GPIOL_VALUE = idp_cpld_gpiol_value_shadow;\
++}
++
++#define WRITE_IDP_CONTROL_PORT(value, mask) \
++{\
++ idp_control_port_shadow = ((value & mask) | (idp_control_port_shadow & ~mask));\
++ (*((volatile unsigned long *)IDP_CTRL_PORT_BASE)) = idp_control_port_shadow;\
++}
++
++#endif
++
++/* A listing of interrupts used by external hardware devices */
++
++#define TOUCH_PANEL_IRQ IRQ_GPIO(21)
++#define TOUCH_PANEL_IRQ_EGDE GPIO_FALLING_EDGE
++
++#define ETHERNET_IRQ IRQ_GPIO(4)
++#define ETHERNET_IRQ_EDGE GPIO_RISING_EDGE
++
++/*
++ * Bit masks for various registers
++ */
++
++
++/* control port */
++#define IDP_CONTROL_PORT_PCSLOT0_0 (1 << 0)
++#define IDP_CONTROL_PORT_PCSLOT0_1 (1 << 1)
++#define IDP_CONTROL_PORT_PCSLOT0_2 (1 << 2)
++#define IDP_CONTROL_PORT_PCSLOT0_3 (1 << 3)
++#define IDP_CONTROL_PORT_PCSLOT1_1 (1 << 4)
++#define IDP_CONTROL_PORT_PCSLOT1_2 (1 << 5)
++#define IDP_CONTROL_PORT_PCSLOT1_3 (1 << 6)
++#define IDP_CONTROL_PORT_PCSLOT1_4 (1 << 7)
++#define IDP_CONTROL_PORT_SERIAL1_EN (1 << 9)
++#define IDP_CONTROL_PORT_SERIAL2_EN (1 << 10)
++#define IDP_CONTROL_PORT_SERIAL3_EN (1 << 11)
++#define IDP_CONTROL_PORT_IRDA_FIR (1 << 12)
++#define IDP_CONTROL_PORT_IRDA_M0 (1 << 13)
++#define IDP_CONTROL_PORT_IRDA_M1 (1 << 14)
++#define IDP_CONTROL_PORT_I2S_PWR (1 << 15)
++#define IDP_CONTROL_PORT_FLASH_WP (1 << 19)
++#define IDP_CONTROL_PORT_MILL_EN (1 << 20)
++#define IDP_CONTROL_PORT_LCD_PWR (1 << 21)
++#define IDP_CONTROL_PORT_LCD_BKLEN (1 << 22)
++#define IDP_CONTROL_PORT_LCD_ENAVLCD (1 << 23)
++
++/*
++ * Macros for LCD Driver
++ */
++
++#ifdef CONFIG_FB_PXA
++
++#define FB_BACKLIGHT_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_BKLEN, IDP_CONTROL_PORT_LCD_BKLEN)
++#define FB_BACKLIGHT_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_BKLEN)
++
++#define FB_PWR_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_PWR, IDP_CONTROL_PORT_LCD_PWR)
++#define FB_PWR_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_PWR)
++
++#define FB_VLCD_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_ENAVLCD, IDP_CONTROL_PORT_LCD_ENAVLCD)
++#define FB_VLCD_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_ENAVLCD)
++
++#endif
++
++
++/*
++ * Macros for LED Driver
++ */
++
++/* leds 0 = ON */
++#define IDP_HB_LED 0x1
++#define IDP_BUSY_LED 0x2
++
++#define IDP_LEDS_MASK (IDP_HB_LED | IDP_BUSY_LED)
++
++#define IDP_WRITE_LEDS(value) WRITE_IDP_CPLD_LED_CONTROL(value, IDP_LEDS_MASK)
++
++/*
++ * macros for MTD driver
++ */
++
++#define FLASH_WRITE_PROTECT_DISABLE() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_FLASH_WP)
++#define FLASH_WRITE_PROTECT_ENABLE() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_FLASH_WP, IDP_CONTROL_PORT_FLASH_WP)
++
++#endif
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/innokom.h
+@@ -0,0 +1,47 @@
++/*
++ * linux/include/asm-arm/arch-pxa/innokom.h
++ *
++ * (c) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/*
++ * GPIOs
++ */
++#define GPIO_INNOKOM_RESET 3
++#define GPIO_INNOKOM_SW_UPDATE 11
++#define GPIO_INNOKOM_ETH 59
++
++/*
++ * ethernet chip (SMSC91C111)
++ */
++#define INNOKOM_ETH_PHYS PXA_CS5_PHYS
++#define INNOKOM_ETH_BASE (0xf0000000) /* phys 0x14000000 */
++#define INNOKOM_ETH_SIZE (1*1024*1024)
++#define INNOKOM_ETH_IRQ IRQ_GPIO(GPIO_INNOKOM_ETH)
++#define INNOKOM_ETH_IRQ_EDGE GPIO_RISING_EDGE
++
++/*
++ * virtual to physical conversion macros
++ */
++#define INNOKOM_P2V(x) ((x) - INNOKOM_FPGA_PHYS + INNOKOM_FPGA_VIRT)
++#define INNOKOM_V2P(x) ((x) - INNOKOM_FPGA_VIRT + INNOKOM_FPGA_PHYS)
++
++#ifndef __ASSEMBLY__
++# define __INNOKOM_REG(x) (*((volatile unsigned long *)INNOKOM_P2V(x)))
++#else
++# define __INNOKOM_REG(x) INNOKOM_P2V(x)
++#endif
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/io.h
+@@ -0,0 +1,34 @@
++/*
++ * linux/include/asm-arm/arch-pxa/io.h
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++#define IO_SPACE_LIMIT 0xffffffff
++
++/*
++ * We don't actually have real ISA nor PCI buses, but there is so many
++ * drivers out there that might just work if we fake them...
++ */
++#define __io(a) (a)
++#define __mem_pci(a) ((unsigned long)(a))
++#define __mem_isa(a) ((unsigned long)(a))
++
++/*
++ * Generic virtual read/write
++ */
++#define __arch_getw(a) (*(volatile unsigned short *)(a))
++#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v))
++
++#define iomem_valid_addr(iomem,sz) (1)
++#define iomem_to_phys(iomem) (iomem)
++
++#endif
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/irq.h
+@@ -0,0 +1,19 @@
++/*
++ * linux/include/asm-arm/arch-pxa/irq.h
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#define fixup_irq(x) (x)
++
++/*
++ * This prototype is required for cascading of multiplexed interrupts.
++ * Since it doesn't exist elsewhere, we'll put it here for now.
++ */
++extern void do_IRQ(int irq, struct pt_regs *regs);
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/irqs.h
+@@ -0,0 +1,137 @@
++/*
++ * linux/include/asm-arm/arch-pxa/irqs.h
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#define PXA_IRQ_SKIP 7 /* The first 7 IRQs are not yet used */
++#define PXA_IRQ(x) ((x) - PXA_IRQ_SKIP)
++
++#define IRQ_HWUART PXA_IRQ(7) /* HWUART Transmit/Receive/Error */
++#define IRQ_GPIO0 PXA_IRQ(8) /* GPIO0 Edge Detect */
++#define IRQ_GPIO1 PXA_IRQ(9) /* GPIO1 Edge Detect */
++#define IRQ_GPIO_2_80 PXA_IRQ(10) /* GPIO[2-80] Edge Detect */
++#define IRQ_USB PXA_IRQ(11) /* USB Service */
++#define IRQ_PMU PXA_IRQ(12) /* Performance Monitoring Unit */
++#define IRQ_I2S PXA_IRQ(13) /* I2S Interrupt */
++#define IRQ_AC97 PXA_IRQ(14) /* AC97 Interrupt */
++#define IRQ_ASSP PXA_IRQ(15) /* Audio SSP Service Request */
++#define IRQ_NSSP PXA_IRQ(16) /* Network SSP Service Request */
++#define IRQ_LCD PXA_IRQ(17) /* LCD Controller Service Request */
++#define IRQ_I2C PXA_IRQ(18) /* I2C Service Request */
++#define IRQ_ICP PXA_IRQ(19) /* ICP Transmit/Receive/Error */
++#define IRQ_STUART PXA_IRQ(20) /* STUART Transmit/Receive/Error */
++#define IRQ_BTUART PXA_IRQ(21) /* BTUART Transmit/Receive/Error */
++#define IRQ_FFUART PXA_IRQ(22) /* FFUART Transmit/Receive/Error*/
++#define IRQ_MMC PXA_IRQ(23) /* MMC Status/Error Detection */
++#define IRQ_SSP PXA_IRQ(24) /* SSP Service Request */
++#define IRQ_DMA PXA_IRQ(25) /* DMA Channel Service Request */
++#define IRQ_OST0 PXA_IRQ(26) /* OS Timer match 0 */
++#define IRQ_OST1 PXA_IRQ(27) /* OS Timer match 1 */
++#define IRQ_OST2 PXA_IRQ(28) /* OS Timer match 2 */
++#define IRQ_OST3 PXA_IRQ(29) /* OS Timer match 3 */
++#define IRQ_RTC1Hz PXA_IRQ(30) /* RTC HZ Clock Tick */
++#define IRQ_RTCAlrm PXA_IRQ(31) /* RTC Alarm */
++
++#define GPIO_2_80_TO_IRQ(x) \
++ PXA_IRQ((x) - 2 + 32)
++#define IRQ_GPIO(x) (((x) < 2) ? (IRQ_GPIO0 + (x)) : GPIO_2_80_TO_IRQ(x))
++
++#define IRQ_TO_GPIO_2_80(i) \
++ ((i) - PXA_IRQ(32) + 2)
++#define IRQ_TO_GPIO(i) ((i) - (((i) > IRQ_GPIO1) ? IRQ_GPIO(2) - 2 : IRQ_GPIO(0)))
++
++#define NR_IRQS (IRQ_GPIO(80) + 1)
++
++#if defined(CONFIG_SA1111)
++
++#define IRQ_SA1111_START (IRQ_GPIO(80) + 1)
++#define SA1111_IRQ(x) (IRQ_SA1111_START + (x))
++
++#define IRQ_GPAIN0 SA1111_IRQ(0)
++#define IRQ_GPAIN1 SA1111_IRQ(1)
++#define IRQ_GPAIN2 SA1111_IRQ(2)
++#define IRQ_GPAIN3 SA1111_IRQ(3)
++#define IRQ_GPBIN0 SA1111_IRQ(4)
++#define IRQ_GPBIN1 SA1111_IRQ(5)
++#define IRQ_GPBIN2 SA1111_IRQ(6)
++#define IRQ_GPBIN3 SA1111_IRQ(7)
++#define IRQ_GPBIN4 SA1111_IRQ(8)
++#define IRQ_GPBIN5 SA1111_IRQ(9)
++#define IRQ_GPCIN0 SA1111_IRQ(10)
++#define IRQ_GPCIN1 SA1111_IRQ(11)
++#define IRQ_GPCIN2 SA1111_IRQ(12)
++#define IRQ_GPCIN3 SA1111_IRQ(13)
++#define IRQ_GPCIN4 SA1111_IRQ(14)
++#define IRQ_GPCIN5 SA1111_IRQ(15)
++#define IRQ_GPCIN6 SA1111_IRQ(16)
++#define IRQ_GPCIN7 SA1111_IRQ(17)
++#define IRQ_MSTXINT SA1111_IRQ(18)
++#define IRQ_MSRXINT SA1111_IRQ(19)
++#define IRQ_MSSTOPERRINT SA1111_IRQ(20)
++#define IRQ_TPTXINT SA1111_IRQ(21)
++#define IRQ_TPRXINT SA1111_IRQ(22)
++#define IRQ_TPSTOPERRINT SA1111_IRQ(23)
++#define SSPXMTINT SA1111_IRQ(24)
++#define SSPRCVINT SA1111_IRQ(25)
++#define SSPROR SA1111_IRQ(26)
++#define AUDXMTDMADONEA SA1111_IRQ(32)
++#define AUDRCVDMADONEA SA1111_IRQ(33)
++#define AUDXMTDMADONEB SA1111_IRQ(34)
++#define AUDRCVDMADONEB SA1111_IRQ(35)
++#define AUDTFSR SA1111_IRQ(36)
++#define AUDRFSR SA1111_IRQ(37)
++#define AUDTUR SA1111_IRQ(38)
++#define AUDROR SA1111_IRQ(39)
++#define AUDDTS SA1111_IRQ(40)
++#define AUDRDD SA1111_IRQ(41)
++#define AUDSTO SA1111_IRQ(42)
++#define USBPWR SA1111_IRQ(43)
++#define NIRQHCIM SA1111_IRQ(44)
++#define HCIBUFFACC SA1111_IRQ(45)
++#define HCIRMTWKP SA1111_IRQ(46)
++#define NHCIMFCIR SA1111_IRQ(47)
++#define PORT_RESUME SA1111_IRQ(48)
++#define S0_READY_NINT SA1111_IRQ(49)
++#define S1_READY_NINT SA1111_IRQ(50)
++#define S0_CD_VALID SA1111_IRQ(51)
++#define S1_CD_VALID SA1111_IRQ(52)
++#define S0_BVD1_STSCHG SA1111_IRQ(53)
++#define S1_BVD1_STSCHG SA1111_IRQ(54)
++
++#define SA1111_IRQ_MAX SA1111_IRQ(54)
++
++#undef NR_IRQS
++#define NR_IRQS (SA1111_IRQ_MAX + 1)
++
++#endif // defined(CONFIG_SA1111)
++
++#if defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_PXA_IDP)
++#if CONFIG_SA1111
++#define LUBBOCK_IRQ(x) (SA1111_IRQ_MAX + 1 + (x))
++#else
++#define LUBBOCK_IRQ(x) (IRQ_GPIO(80) + 1 + (x))
++#endif
++
++#define LUBBOCK_SD_IRQ LUBBOCK_IRQ(0)
++#define LUBBOCK_SA1111_IRQ LUBBOCK_IRQ(1)
++#define LUBBOCK_USB_IRQ LUBBOCK_IRQ(2)
++#define LUBBOCK_ETH_IRQ LUBBOCK_IRQ(3)
++#define LUBBOCK_UCB1400_IRQ LUBBOCK_IRQ(4)
++#define LUBBOCK_BB_IRQ LUBBOCK_IRQ(5)
++#define LUBBOCK_USB_DISC_IRQ LUBBOCK_IRQ(6) /* usb disconnect */
++#define LUBBOCK_LAST_IRQ LUBBOCK_IRQ(6)
++
++#undef NR_IRQS
++#define NR_IRQS (LUBBOCK_LAST_IRQ + 1)
++
++#endif // CONFIG_ARCH_LUBBOCK
++
++
++
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/keyboard.h
+@@ -0,0 +1,29 @@
++/*
++ * linux/include/asm-arm/arch-pxa/keyboard.h
++ *
++ * This file contains the architecture specific keyboard definitions
++ */
++
++#ifndef _PXA_KEYBOARD_H
++#define _PXA_KEYBOARD_H
++
++#include <linux/config.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++
++extern struct kbd_ops_struct *kbd_ops;
++
++#define kbd_disable_irq() do { } while(0);
++#define kbd_enable_irq() do { } while(0);
++
++extern int sa1111_kbd_init_hw(void);
++
++static inline void kbd_init_hw(void)
++{
++ if (machine_is_lubbock())
++ sa1111_kbd_init_hw();
++}
++
++
++#endif /* _PXA_KEYBOARD_H */
++
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/lubbock.h
+@@ -0,0 +1,113 @@
++/*
++ * linux/include/asm-arm/arch-pxa/lubbock.h
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#define LUBBOCK_FPGA_PHYS PXA_CS2_PHYS
++#define LUBBOCK_FPGA_VIRT (0xf0000000) /* phys 0x08000000 */
++#define LUBBOCK_ETH_PHYS PXA_CS3_PHYS
++#define LUBBOCK_ETH_VIRT (0xf1000000)
++#define LUBBOCK_SA1111_BASE (0xf4000000) /* phys 0x10000000 */
++
++#define LUB_P2V(x) ((x) - LUBBOCK_FPGA_PHYS + LUBBOCK_FPGA_VIRT)
++#define LUB_V2P(x) ((x) - LUBBOCK_FPGA_VIRT + LUBBOCK_FPGA_PHYS)
++
++#ifndef __ASSEMBLY__
++# define __LUB_REG(x) (*((volatile unsigned long *)LUB_P2V(x)))
++#else
++# define __LUB_REG(x) LUB_P2V(x)
++#endif
++
++/* board level registers in the CPLD: (offsets from CPLD_BASE) */
++
++#define WHOAMI 0 // card ID's (see programmers manual)
++#define HEX_LED 0x10 // R/W access to 8 7 segment displays
++#define DISC_BLNK_LED 0x40 // R/W [15-8] enables for hex leds, [7-0] discrete LEDs
++#define CONF_SWITCHES 0x50 // RO [1] flash wrt prot, [0] 0= boot from rom, 1= flash
++#define USER_SWITCHES 0x60 // RO [15-8] dip switches, [7-0] 2 hex encoding switches
++#define MISC_WR 0x80 // R/W various system controls -see manual
++#define MISC_RD 0x90 // RO various system status bits -see manual
++//#define LUB_IRQ_MASK_EN 0xC0 // R/W 0= mask, 1= enable of TS, codec, ethernet, USB, SA1111, and card det. irq's
++//#define LUB_IRQ_SET_CLR 0xD0 // R/W 1= set, 0 = clear IRQ's from TS, codec, etc...
++//#define LUB_GP 0x100 // R/W [15-0] 16 bits of general purpose I/o for hacking
++
++
++/* FPGA register physical addresses */
++#define _LUB_WHOAMI (LUBBOCK_FPGA_PHYS + 0x000)
++#define _LUB_HEXLED (LUBBOCK_FPGA_PHYS + 0x010)
++#define _LUB_DISC_BLNK_LED (LUBBOCK_FPGA_PHYS + 0x040)
++#define _LUB_CONF_SWITCHES (LUBBOCK_FPGA_PHYS + 0x050)
++#define _LUB_USER_SWITCHES (LUBBOCK_FPGA_PHYS + 0x060)
++#define _LUB_MISC_WR (LUBBOCK_FPGA_PHYS + 0x080)
++#define _LUB_MISC_RD (LUBBOCK_FPGA_PHYS + 0x090)
++#define _LUB_IRQ_MASK_EN (LUBBOCK_FPGA_PHYS + 0x0C0)
++#define _LUB_IRQ_SET_CLR (LUBBOCK_FPGA_PHYS + 0x0D0)
++#define _LUB_GP (LUBBOCK_FPGA_PHYS + 0x100)
++
++/* FPGA register virtual addresses */
++#define LUB_WHOAMI __LUB_REG(_LUB_WHOAMI)
++#define LUB_HEXLED __LUB_REG(_LUB_HEXLED)
++#define LUB_DISC_BLNK_LED __LUB_REG(_LUB_DISC_BLNK_LED)
++#define LUB_CONF_SWITCHES __LUB_REG(_LUB_CONF_SWITCHES)
++#define LUB_USER_SWITCHES __LUB_REG(_LUB_USER_SWITCHES)
++#define LUB_MISC_WR __LUB_REG(_LUB_MISC_WR)
++#define LUB_MISC_RD __LUB_REG(_LUB_MISC_RD)
++#define LUB_IRQ_MASK_EN __LUB_REG(_LUB_IRQ_MASK_EN)
++#define LUB_IRQ_SET_CLR __LUB_REG(_LUB_IRQ_SET_CLR)
++#define LUB_GP __LUB_REG(_LUB_GP)
++
++/* GPIOs */
++
++#define GPIO_LUBBOCK_IRQ 0
++#define IRQ_GPIO_LUBBOCK_IRQ IRQ_GPIO0
++
++
++/*
++ * LED macros
++ */
++
++#define LEDS_BASE LUB_DISC_BLNK_LED
++
++// 8 discrete leds available for general use:
++
++#define D28 0x1
++#define D27 0x2
++#define D26 0x4
++#define D25 0x8
++#define D24 0x10
++#define D23 0x20
++#define D22 0x40
++#define D21 0x80
++
++/* Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays so
++* be sure to not monkey with them here.
++*/
++
++#define HEARTBEAT_LED D28
++#define SYS_BUSY_LED D27
++#define HEXLEDS_BASE LUB_HEXLED
++
++#define HEARTBEAT_LED_ON (LEDS_BASE &= ~HEARTBEAT_LED)
++#define HEARTBEAT_LED_OFF (LEDS_BASE |= HEARTBEAT_LED)
++#define SYS_BUSY_LED_OFF (LEDS_BASE |= SYS_BUSY_LED)
++#define SYS_BUSY_LED_ON (LEDS_BASE &= ~SYS_BUSY_LED)
++
++// use x = D26-D21 for these, please...
++#define DISCRETE_LED_ON(x) (LEDS_BASE &= ~(x))
++#define DISCRETE_LED_OFF(x) (LEDS_BASE |= (x))
++
++#ifndef __ASSEMBLY__
++
++//extern int hexled_val = 0;
++
++#endif
++
++#define BUMP_COUNTER (HEXLEDS_BASE = hexled_val++)
++#define DEC_COUNTER (HEXLEDS_BASE = hexled_val--)
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/memory.h
+@@ -0,0 +1,106 @@
++/*
++ * linux/include/asm-arm/arch-pxa/memory.h
++ *
++ * Author: Nicolas Pitre
++ * Copyright: (C) 2001 MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef __ASM_ARCH_MEMORY_H
++#define __ASM_ARCH_MEMORY_H
++
++
++/*
++ * Task size: 3GB
++ */
++#define TASK_SIZE (0xc0000000UL)
++#define TASK_SIZE_26 (0x04000000UL)
++
++/*
++ * This decides where the kernel will search for a free chunk of vm
++ * space during mmap's.
++ */
++#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
++
++/*
++ * Page offset: 3GB
++ */
++#define PAGE_OFFSET (0xc0000000UL)
++
++/*
++ * Physical DRAM offset.
++ */
++#define PHYS_OFFSET (0xa0000000UL)
++
++/*
++ * physical vs virtual ram conversion
++ */
++#define __virt_to_phys__is_a_macro
++#define __phys_to_virt__is_a_macro
++#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
++#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
++
++/*
++ * Virtual view <-> DMA view memory address translations
++ * virt_to_bus: Used to translate the virtual address to an
++ * address suitable to be passed to set_dma_addr
++ * bus_to_virt: Used to convert an address for DMA operations
++ * to an address that the kernel can use.
++ */
++#define __virt_to_bus__is_a_macro
++#define __bus_to_virt__is_a_macro
++#define __virt_to_bus(x) __virt_to_phys(x)
++#define __bus_to_virt(x) __phys_to_virt(x)
++
++#ifdef CONFIG_DISCONTIGMEM
++/*
++ * The nodes are matched with the physical SDRAM banks as follows:
++ *
++ * node 0: 0xa0000000-0xa3ffffff --> 0xc0000000-0xc3ffffff
++ * node 1: 0xa4000000-0xa7ffffff --> 0xc4000000-0xc7ffffff
++ * node 2: 0xa8000000-0xabffffff --> 0xc8000000-0xcbffffff
++ * node 3: 0xac000000-0xafffffff --> 0xcc000000-0xcfffffff
++ */
++
++#define NR_NODES 4
++
++/*
++ * Given a kernel address, find the home node of the underlying memory.
++ */
++#define KVADDR_TO_NID(addr) (((unsigned long)(addr) - PAGE_OFFSET) >> 26)
++
++/*
++ * Given a page frame number, convert it to a node id.
++ */
++#define PFN_TO_NID(pfn) (((pfn) - PHYS_PFN_OFFSET) >> (26 - PAGE_SHIFT))
++
++/*
++ * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
++ * and returns the mem_map of that node.
++ */
++#define ADDR_TO_MAPBASE(kaddr) NODE_MEM_MAP(KVADDR_TO_NID(kaddr))
++
++/*
++ * Given a page frame number, find the owning node of the memory
++ * and returns the mem_map of that node.
++ */
++#define PFN_TO_MAPBASE(pfn) NODE_MEM_MAP(PFN_TO_NID(pfn))
++
++/*
++ * Given a kaddr, LOCAL_MEM_MAP finds the owning node of the memory
++ * and returns the index corresponding to the appropriate page in the
++ * node's mem_map.
++ */
++#define LOCAL_MAP_NR(addr) \
++ (((unsigned long)(addr) & 0x03ffffff) >> PAGE_SHIFT)
++
++#else
++
++#define PFN_TO_NID(addr) (0)
++
++#endif
++
++#endif
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/param.h
+@@ -0,0 +1,3 @@
++/*
++ * linux/include/asm-arm/arch-pxa/param.h
++ */
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/pcmcia.h
+@@ -0,0 +1,65 @@
++/*
++ * linux/include/asm-arm/arch-pxa/pcmcia.h
++ *
++ * Author: George Davis
++ * Created: Jan 10, 2002
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *
++ * Originally based upon linux/include/asm-arm/arch-sa1100/pcmcia.h
++ *
++ */
++
++#ifndef _ASM_ARCH_PCMCIA
++#define _ASM_ARCH_PCMCIA
++
++
++/* Ideally, we'd support up to MAX_SOCK sockets, but PXA250 only
++ * provides support for a maximum of two.
++ */
++#define PXA_PCMCIA_MAX_SOCK (2)
++
++
++#ifndef __ASSEMBLY__
++
++struct pcmcia_init {
++ void (*handler)(int irq, void *dev, struct pt_regs *regs);
++};
++
++struct pcmcia_state {
++ unsigned detect: 1,
++ ready: 1,
++ bvd1: 1,
++ bvd2: 1,
++ wrprot: 1,
++ vs_3v: 1,
++ vs_Xv: 1;
++};
++
++struct pcmcia_state_array {
++ unsigned int size;
++ struct pcmcia_state *state;
++};
++
++struct pcmcia_irq_info {
++ unsigned int sock;
++ unsigned int irq;
++};
++
++struct pcmcia_low_level {
++ int (*init)(struct pcmcia_init *);
++ int (*shutdown)(void);
++ int (*socket_state)(struct pcmcia_state_array *);
++ int (*get_irq_info)(struct pcmcia_irq_info *);
++ int (*configure_socket)(unsigned int, socket_state_t *);
++};
++
++extern struct pcmcia_low_level *pcmcia_low_level;
++
++#endif /* __ASSEMBLY__ */
++
++#endif
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/pxa-regs.h
+@@ -0,0 +1,1327 @@
++/*
++ * linux/include/asm-arm/arch-pxa/pxa-regs.h
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef _PXA_REGS_H_
++#define _PXA_REGS_H_
++
++#include "bitfield.h"
++
++
++// FIXME hack so that SA-1111.h will work [cb]
++
++#ifndef __ASSEMBLY__
++typedef unsigned short Word16 ;
++typedef unsigned int Word32 ;
++typedef Word32 Word ;
++typedef Word Quad [4] ;
++typedef void *Address ;
++typedef void (*ExcpHndlr) (void) ;
++#endif
++
++/*
++ * PXA Chip selects
++ */
++
++#define PXA_CS0_PHYS 0x00000000
++#define PXA_CS1_PHYS 0x04000000
++#define PXA_CS2_PHYS 0x08000000
++#define PXA_CS3_PHYS 0x0C000000
++#define PXA_CS4_PHYS 0x10000000
++#define PXA_CS5_PHYS 0x14000000
++
++
++/*
++ * Personal Computer Memory Card International Association (PCMCIA) sockets
++ */
++
++#define PCMCIAPrtSp 0x04000000 /* PCMCIA Partition Space [byte] */
++#define PCMCIASp (4*PCMCIAPrtSp) /* PCMCIA Space [byte] */
++#define PCMCIAIOSp PCMCIAPrtSp /* PCMCIA I/O Space [byte] */
++#define PCMCIAAttrSp PCMCIAPrtSp /* PCMCIA Attribute Space [byte] */
++#define PCMCIAMemSp PCMCIAPrtSp /* PCMCIA Memory Space [byte] */
++
++#define PCMCIA0Sp PCMCIASp /* PCMCIA 0 Space [byte] */
++#define PCMCIA0IOSp PCMCIAIOSp /* PCMCIA 0 I/O Space [byte] */
++#define PCMCIA0AttrSp PCMCIAAttrSp /* PCMCIA 0 Attribute Space [byte] */
++#define PCMCIA0MemSp PCMCIAMemSp /* PCMCIA 0 Memory Space [byte] */
++
++#define PCMCIA1Sp PCMCIASp /* PCMCIA 1 Space [byte] */
++#define PCMCIA1IOSp PCMCIAIOSp /* PCMCIA 1 I/O Space [byte] */
++#define PCMCIA1AttrSp PCMCIAAttrSp /* PCMCIA 1 Attribute Space [byte] */
++#define PCMCIA1MemSp PCMCIAMemSp /* PCMCIA 1 Memory Space [byte] */
++
++#define _PCMCIA(Nb) /* PCMCIA [0..1] */ \
++ (0x20000000 + (Nb)*PCMCIASp)
++#define _PCMCIAIO(Nb) _PCMCIA (Nb) /* PCMCIA I/O [0..1] */
++#define _PCMCIAAttr(Nb) /* PCMCIA Attribute [0..1] */ \
++ (_PCMCIA (Nb) + 2*PCMCIAPrtSp)
++#define _PCMCIAMem(Nb) /* PCMCIA Memory [0..1] */ \
++ (_PCMCIA (Nb) + 3*PCMCIAPrtSp)
++
++#define _PCMCIA0 _PCMCIA (0) /* PCMCIA 0 */
++#define _PCMCIA0IO _PCMCIAIO (0) /* PCMCIA 0 I/O */
++#define _PCMCIA0Attr _PCMCIAAttr (0) /* PCMCIA 0 Attribute */
++#define _PCMCIA0Mem _PCMCIAMem (0) /* PCMCIA 0 Memory */
++
++#define _PCMCIA1 _PCMCIA (1) /* PCMCIA 1 */
++#define _PCMCIA1IO _PCMCIAIO (1) /* PCMCIA 1 I/O */
++#define _PCMCIA1Attr _PCMCIAAttr (1) /* PCMCIA 1 Attribute */
++#define _PCMCIA1Mem _PCMCIAMem (1) /* PCMCIA 1 Memory */
++
++
++
++/*
++ * DMA Controller
++ */
++
++#define DCSR0 __REG(0x40000000) /* DMA Control / Status Register for Channel 0 */
++#define DCSR1 __REG(0x40000004) /* DMA Control / Status Register for Channel 1 */
++#define DCSR2 __REG(0x40000008) /* DMA Control / Status Register for Channel 2 */
++#define DCSR3 __REG(0x4000000c) /* DMA Control / Status Register for Channel 3 */
++#define DCSR4 __REG(0x40000010) /* DMA Control / Status Register for Channel 4 */
++#define DCSR5 __REG(0x40000014) /* DMA Control / Status Register for Channel 5 */
++#define DCSR6 __REG(0x40000018) /* DMA Control / Status Register for Channel 6 */
++#define DCSR7 __REG(0x4000001c) /* DMA Control / Status Register for Channel 7 */
++#define DCSR8 __REG(0x40000020) /* DMA Control / Status Register for Channel 8 */
++#define DCSR9 __REG(0x40000024) /* DMA Control / Status Register for Channel 9 */
++#define DCSR10 __REG(0x40000028) /* DMA Control / Status Register for Channel 10 */
++#define DCSR11 __REG(0x4000002c) /* DMA Control / Status Register for Channel 11 */
++#define DCSR12 __REG(0x40000030) /* DMA Control / Status Register for Channel 12 */
++#define DCSR13 __REG(0x40000034) /* DMA Control / Status Register for Channel 13 */
++#define DCSR14 __REG(0x40000038) /* DMA Control / Status Register for Channel 14 */
++#define DCSR15 __REG(0x4000003c) /* DMA Control / Status Register for Channel 15 */
++
++#define DCSR(x) __REG2(0x40000000, (x) << 2)
++
++#define DCSR_RUN (1 << 31) /* Run Bit (read / write) */
++#define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch (read / write) */
++#define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable (read / write) */
++#define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */
++#define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */
++#define DCSR_ENDINTR (1 << 2) /* End Interrupt (read / write) */
++#define DCSR_STARTINTR (1 << 1) /* Start Interrupt (read / write) */
++#define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt (read / write) */
++
++#define DINT __REG(0x400000f0) /* DMA Interrupt Register */
++
++#define DRCMR0 __REG(0x40000100) /* Request to Channel Map Register for DREQ 0 */
++#define DRCMR1 __REG(0x40000104) /* Request to Channel Map Register for DREQ 1 */
++#define DRCMR2 __REG(0x40000108) /* Request to Channel Map Register for I2S receive Request */
++#define DRCMR3 __REG(0x4000010c) /* Request to Channel Map Register for I2S transmit Request */
++#define DRCMR4 __REG(0x40000110) /* Request to Channel Map Register for BTUART receive Request */
++#define DRCMR5 __REG(0x40000114) /* Request to Channel Map Register for BTUART transmit Request. */
++#define DRCMR6 __REG(0x40000118) /* Request to Channel Map Register for FFUART receive Request */
++#define DRCMR7 __REG(0x4000011c) /* Request to Channel Map Register for FFUART transmit Request */
++#define DRCMR8 __REG(0x40000120) /* Request to Channel Map Register for AC97 microphone Request */
++#define DRCMR9 __REG(0x40000124) /* Request to Channel Map Register for AC97 modem receive Request */
++#define DRCMR10 __REG(0x40000128) /* Request to Channel Map Register for AC97 modem transmit Request */
++#define DRCMR11 __REG(0x4000012c) /* Request to Channel Map Register for AC97 audio receive Request */
++#define DRCMR12 __REG(0x40000130) /* Request to Channel Map Register for AC97 audio transmit Request */
++#define DRCMR13 __REG(0x40000134) /* Request to Channel Map Register for SSP receive Request */
++#define DRCMR14 __REG(0x40000138) /* Request to Channel Map Register for SSP transmit Request */
++#define DRCMR15 __REG(0x4000013c) /* Reserved */
++#define DRCMR16 __REG(0x40000140) /* Reserved */
++#define DRCMR17 __REG(0x40000144) /* Request to Channel Map Register for ICP receive Request */
++#define DRCMR18 __REG(0x40000148) /* Request to Channel Map Register for ICP transmit Request */
++#define DRCMR19 __REG(0x4000014c) /* Request to Channel Map Register for STUART receive Request */
++#define DRCMR20 __REG(0x40000150) /* Request to Channel Map Register for STUART transmit Request */
++#define DRCMR21 __REG(0x40000154) /* Request to Channel Map Register for MMC receive Request */
++#define DRCMR22 __REG(0x40000158) /* Request to Channel Map Register for MMC transmit Request */
++#define DRCMR23 __REG(0x4000015c) /* Reserved */
++#define DRCMR24 __REG(0x40000160) /* Reserved */
++#define DRCMR25 __REG(0x40000164) /* Request to Channel Map Register for USB endpoint 1 Request */
++#define DRCMR26 __REG(0x40000168) /* Request to Channel Map Register for USB endpoint 2 Request */
++#define DRCMR27 __REG(0x4000016C) /* Request to Channel Map Register for USB endpoint 3 Request */
++#define DRCMR28 __REG(0x40000170) /* Request to Channel Map Register for USB endpoint 4 Request */
++#define DRCMR29 __REG(0x40000174) /* Reserved */
++#define DRCMR30 __REG(0x40000178) /* Request to Channel Map Register for USB endpoint 6 Request */
++#define DRCMR31 __REG(0x4000017C) /* Request to Channel Map Register for USB endpoint 7 Request */
++#define DRCMR32 __REG(0x40000180) /* Request to Channel Map Register for USB endpoint 8 Request */
++#define DRCMR33 __REG(0x40000184) /* Request to Channel Map Register for USB endpoint 9 Request */
++#define DRCMR34 __REG(0x40000188) /* Reserved */
++#define DRCMR35 __REG(0x4000018C) /* Request to Channel Map Register for USB endpoint 11 Request */
++#define DRCMR36 __REG(0x40000190) /* Request to Channel Map Register for USB endpoint 12 Request */
++#define DRCMR37 __REG(0x40000194) /* Request to Channel Map Register for USB endpoint 13 Request */
++#define DRCMR38 __REG(0x40000198) /* Request to Channel Map Register for USB endpoint 14 Request */
++#define DRCMR39 __REG(0x4000019C) /* Reserved */
++
++#define DRCMRRXSADR DRCMR2
++#define DRCMRTXSADR DRCMR3
++#define DRCMRRXBTRBR DRCMR4
++#define DRCMRTXBTTHR DRCMR5
++#define DRCMRRXFFRBR DRCMR6
++#define DRCMRTXFFTHR DRCMR7
++#define DRCMRRXMCDR DRCMR8
++#define DRCMRRXMODR DRCMR9
++#define DRCMRTXMODR DRCMR10
++#define DRCMRRXPCDR DRCMR11
++#define DRCMRTXPCDR DRCMR12
++#define DRCMRRXSSDR DRCMR13
++#define DRCMRTXSSDR DRCMR14
++#define DRCMRRXICDR DRCMR17
++#define DRCMRTXICDR DRCMR18
++#define DRCMRRXSTRBR DRCMR19
++#define DRCMRTXSTTHR DRCMR20
++#define DRCMRRXMMC DRCMR21
++#define DRCMRTXMMC DRCMR22
++
++#define DRCMR_MAPVLD (1 << 7) /* Map Valid (read / write) */
++#define DRCMR_CHLNUM 0x0f /* mask for Channel Number (read / write) */
++
++#define DDADR0 __REG(0x40000200) /* DMA Descriptor Address Register Channel 0 */
++#define DSADR0 __REG(0x40000204) /* DMA Source Address Register Channel 0 */
++#define DTADR0 __REG(0x40000208) /* DMA Target Address Register Channel 0 */
++#define DCMD0 __REG(0x4000020c) /* DMA Command Address Register Channel 0 */
++#define DDADR1 __REG(0x40000210) /* DMA Descriptor Address Register Channel 1 */
++#define DSADR1 __REG(0x40000214) /* DMA Source Address Register Channel 1 */
++#define DTADR1 __REG(0x40000218) /* DMA Target Address Register Channel 1 */
++#define DCMD1 __REG(0x4000021c) /* DMA Command Address Register Channel 1 */
++#define DDADR2 __REG(0x40000220) /* DMA Descriptor Address Register Channel 2 */
++#define DSADR2 __REG(0x40000224) /* DMA Source Address Register Channel 2 */
++#define DTADR2 __REG(0x40000228) /* DMA Target Address Register Channel 2 */
++#define DCMD2 __REG(0x4000022c) /* DMA Command Address Register Channel 2 */
++#define DDADR3 __REG(0x40000230) /* DMA Descriptor Address Register Channel 3 */
++#define DSADR3 __REG(0x40000234) /* DMA Source Address Register Channel 3 */
++#define DTADR3 __REG(0x40000238) /* DMA Target Address Register Channel 3 */
++#define DCMD3 __REG(0x4000023c) /* DMA Command Address Register Channel 3 */
++#define DDADR4 __REG(0x40000240) /* DMA Descriptor Address Register Channel 4 */
++#define DSADR4 __REG(0x40000244) /* DMA Source Address Register Channel 4 */
++#define DTADR4 __REG(0x40000248) /* DMA Target Address Register Channel 4 */
++#define DCMD4 __REG(0x4000024c) /* DMA Command Address Register Channel 4 */
++#define DDADR5 __REG(0x40000250) /* DMA Descriptor Address Register Channel 5 */
++#define DSADR5 __REG(0x40000254) /* DMA Source Address Register Channel 5 */
++#define DTADR5 __REG(0x40000258) /* DMA Target Address Register Channel 5 */
++#define DCMD5 __REG(0x4000025c) /* DMA Command Address Register Channel 5 */
++#define DDADR6 __REG(0x40000260) /* DMA Descriptor Address Register Channel 6 */
++#define DSADR6 __REG(0x40000264) /* DMA Source Address Register Channel 6 */
++#define DTADR6 __REG(0x40000268) /* DMA Target Address Register Channel 6 */
++#define DCMD6 __REG(0x4000026c) /* DMA Command Address Register Channel 6 */
++#define DDADR7 __REG(0x40000270) /* DMA Descriptor Address Register Channel 7 */
++#define DSADR7 __REG(0x40000274) /* DMA Source Address Register Channel 7 */
++#define DTADR7 __REG(0x40000278) /* DMA Target Address Register Channel 7 */
++#define DCMD7 __REG(0x4000027c) /* DMA Command Address Register Channel 7 */
++#define DDADR8 __REG(0x40000280) /* DMA Descriptor Address Register Channel 8 */
++#define DSADR8 __REG(0x40000284) /* DMA Source Address Register Channel 8 */
++#define DTADR8 __REG(0x40000288) /* DMA Target Address Register Channel 8 */
++#define DCMD8 __REG(0x4000028c) /* DMA Command Address Register Channel 8 */
++#define DDADR9 __REG(0x40000290) /* DMA Descriptor Address Register Channel 9 */
++#define DSADR9 __REG(0x40000294) /* DMA Source Address Register Channel 9 */
++#define DTADR9 __REG(0x40000298) /* DMA Target Address Register Channel 9 */
++#define DCMD9 __REG(0x4000029c) /* DMA Command Address Register Channel 9 */
++#define DDADR10 __REG(0x400002a0) /* DMA Descriptor Address Register Channel 10 */
++#define DSADR10 __REG(0x400002a4) /* DMA Source Address Register Channel 10 */
++#define DTADR10 __REG(0x400002a8) /* DMA Target Address Register Channel 10 */
++#define DCMD10 __REG(0x400002ac) /* DMA Command Address Register Channel 10 */
++#define DDADR11 __REG(0x400002b0) /* DMA Descriptor Address Register Channel 11 */
++#define DSADR11 __REG(0x400002b4) /* DMA Source Address Register Channel 11 */
++#define DTADR11 __REG(0x400002b8) /* DMA Target Address Register Channel 11 */
++#define DCMD11 __REG(0x400002bc) /* DMA Command Address Register Channel 11 */
++#define DDADR12 __REG(0x400002c0) /* DMA Descriptor Address Register Channel 12 */
++#define DSADR12 __REG(0x400002c4) /* DMA Source Address Register Channel 12 */
++#define DTADR12 __REG(0x400002c8) /* DMA Target Address Register Channel 12 */
++#define DCMD12 __REG(0x400002cc) /* DMA Command Address Register Channel 12 */
++#define DDADR13 __REG(0x400002d0) /* DMA Descriptor Address Register Channel 13 */
++#define DSADR13 __REG(0x400002d4) /* DMA Source Address Register Channel 13 */
++#define DTADR13 __REG(0x400002d8) /* DMA Target Address Register Channel 13 */
++#define DCMD13 __REG(0x400002dc) /* DMA Command Address Register Channel 13 */
++#define DDADR14 __REG(0x400002e0) /* DMA Descriptor Address Register Channel 14 */
++#define DSADR14 __REG(0x400002e4) /* DMA Source Address Register Channel 14 */
++#define DTADR14 __REG(0x400002e8) /* DMA Target Address Register Channel 14 */
++#define DCMD14 __REG(0x400002ec) /* DMA Command Address Register Channel 14 */
++#define DDADR15 __REG(0x400002f0) /* DMA Descriptor Address Register Channel 15 */
++#define DSADR15 __REG(0x400002f4) /* DMA Source Address Register Channel 15 */
++#define DTADR15 __REG(0x400002f8) /* DMA Target Address Register Channel 15 */
++#define DCMD15 __REG(0x400002fc) /* DMA Command Address Register Channel 15 */
++
++#define DDADR(x) __REG2(0x40000200, (x) << 4)
++#define DSADR(x) __REG2(0x40000204, (x) << 4)
++#define DTADR(x) __REG2(0x40000208, (x) << 4)
++#define DCMD(x) __REG2(0x4000020c, (x) << 4)
++
++#define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor (mask) */
++#define DDADR_STOP (1 << 0) /* Stop (read / write) */
++
++#define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */
++#define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */
++#define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */
++#define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */
++#define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */
++#define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */
++#define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */
++#define DCMD_BURST8 (1 << 16) /* 8 byte burst */
++#define DCMD_BURST16 (2 << 16) /* 16 byte burst */
++#define DCMD_BURST32 (3 << 16) /* 32 byte burst */
++#define DCMD_WIDTH1 (1 << 14) /* 1 byte width */
++#define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */
++#define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */
++#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */
++
++/* default combinations */
++#define DCMD_RXPCDR (DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4)
++#define DCMD_RXMCDR (DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4)
++#define DCMD_TXPCDR (DCMD_INCSRCADDR|DCMD_FLOWTRG|DCMD_BURST32|DCMD_WIDTH4)
++
++
++/*
++ * UARTs
++ */
++
++/* Full Function UART (FFUART) */
++#define FFUART FFRBR
++#define FFRBR __REG(0x40100000) /* Receive Buffer Register (read only) */
++#define FFTHR __REG(0x40100000) /* Transmit Holding Register (write only) */
++#define FFIER __REG(0x40100004) /* Interrupt Enable Register (read/write) */
++#define FFIIR __REG(0x40100008) /* Interrupt ID Register (read only) */
++#define FFFCR __REG(0x40100008) /* FIFO Control Register (write only) */
++#define FFLCR __REG(0x4010000C) /* Line Control Register (read/write) */
++#define FFMCR __REG(0x40100010) /* Modem Control Register (read/write) */
++#define FFLSR __REG(0x40100014) /* Line Status Register (read only) */
++#define FFMSR __REG(0x40100018) /* Modem Status Register (read only) */
++#define FFSPR __REG(0x4010001C) /* Scratch Pad Register (read/write) */
++#define FFISR __REG(0x40100020) /* Infrared Selection Register (read/write) */
++#define FFDLL __REG(0x40100000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */
++#define FFDLH __REG(0x40100004) /* Divisor Latch High Register (DLAB = 1) (read/write) */
++
++/* Bluetooth UART (BTUART) */
++#define BTUART BTRBR
++#define BTRBR __REG(0x40200000) /* Receive Buffer Register (read only) */
++#define BTTHR __REG(0x40200000) /* Transmit Holding Register (write only) */
++#define BTIER __REG(0x40200004) /* Interrupt Enable Register (read/write) */
++#define BTIIR __REG(0x40200008) /* Interrupt ID Register (read only) */
++#define BTFCR __REG(0x40200008) /* FIFO Control Register (write only) */
++#define BTLCR __REG(0x4020000C) /* Line Control Register (read/write) */
++#define BTMCR __REG(0x40200010) /* Modem Control Register (read/write) */
++#define BTLSR __REG(0x40200014) /* Line Status Register (read only) */
++#define BTMSR __REG(0x40200018) /* Modem Status Register (read only) */
++#define BTSPR __REG(0x4020001C) /* Scratch Pad Register (read/write) */
++#define BTISR __REG(0x40200020) /* Infrared Selection Register (read/write) */
++#define BTDLL __REG(0x40200000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */
++#define BTDLH __REG(0x40200004) /* Divisor Latch High Register (DLAB = 1) (read/write) */
++
++/* Standard UART (STUART) */
++#define STUART STRBR
++#define STRBR __REG(0x40700000) /* Receive Buffer Register (read only) */
++#define STTHR __REG(0x40700000) /* Transmit Holding Register (write only) */
++#define STIER __REG(0x40700004) /* Interrupt Enable Register (read/write) */
++#define STIIR __REG(0x40700008) /* Interrupt ID Register (read only) */
++#define STFCR __REG(0x40700008) /* FIFO Control Register (write only) */
++#define STLCR __REG(0x4070000C) /* Line Control Register (read/write) */
++#define STMCR __REG(0x40700010) /* Modem Control Register (read/write) */
++#define STLSR __REG(0x40700014) /* Line Status Register (read only) */
++#define STMSR __REG(0x40700018) /* Reserved */
++#define STSPR __REG(0x4070001C) /* Scratch Pad Register (read/write) */
++#define STISR __REG(0x40700020) /* Infrared Selection Register (read/write) */
++#define STDLL __REG(0x40700000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */
++#define STDLH __REG(0x40700004) /* Divisor Latch High Register (DLAB = 1) (read/write) */
++
++#define IER_DMAE (1 << 7) /* DMA Requests Enable */
++#define IER_UUE (1 << 6) /* UART Unit Enable */
++#define IER_NRZE (1 << 5) /* NRZ coding Enable */
++#define IER_RTIOE (1 << 4) /* Receiver Time Out Interrupt Enable */
++#define IER_MIE (1 << 3) /* Modem Interrupt Enable */
++#define IER_RLSE (1 << 2) /* Receiver Line Status Interrupt Enable */
++#define IER_TIE (1 << 1) /* Transmit Data request Interrupt Enable */
++#define IER_RAVIE (1 << 0) /* Receiver Data Available Interrupt Enable */
++
++#define IIR_FIFOES1 (1 << 7) /* FIFO Mode Enable Status */
++#define IIR_FIFOES0 (1 << 6) /* FIFO Mode Enable Status */
++#define IIR_TOD (1 << 3) /* Time Out Detected */
++#define IIR_IID2 (1 << 2) /* Interrupt Source Encoded */
++#define IIR_IID1 (1 << 1) /* Interrupt Source Encoded */
++#define IIR_IP (1 << 0) /* Interrupt Pending (active low) */
++
++#define FCR_ITL2 (1 << 7) /* Interrupt Trigger Level */
++#define FCR_ITL1 (1 << 6) /* Interrupt Trigger Level */
++#define FCR_RESETTF (1 << 2) /* Reset Transmitter FIFO */
++#define FCR_RESETRF (1 << 1) /* Reset Receiver FIFO */
++#define FCR_TRFIFOE (1 << 0) /* Transmit and Receive FIFO Enable */
++#define FCR_ITL_1 (0)
++#define FCR_ITL_8 (FCR_ITL1)
++#define FCR_ITL_16 (FCR_ITL2)
++#define FCR_ITL_32 (FCR_ITL2|FCR_ITL1)
++
++#define LCR_DLAB (1 << 7) /* Divisor Latch Access Bit */
++#define LCR_SB (1 << 6) /* Set Break */
++#define LCR_STKYP (1 << 5) /* Sticky Parity */
++#define LCR_EPS (1 << 4) /* Even Parity Select */
++#define LCR_PEN (1 << 3) /* Parity Enable */
++#define LCR_STB (1 << 2) /* Stop Bit */
++#define LCR_WLS1 (1 << 1) /* Word Length Select */
++#define LCR_WLS0 (1 << 0) /* Word Length Select */
++
++#define LSR_FIFOE (1 << 7) /* FIFO Error Status */
++#define LSR_TEMT (1 << 6) /* Transmitter Empty */
++#define LSR_TDRQ (1 << 5) /* Transmit Data Request */
++#define LSR_BI (1 << 4) /* Break Interrupt */
++#define LSR_FE (1 << 3) /* Framing Error */
++#define LSR_PE (1 << 2) /* Parity Error */
++#define LSR_OE (1 << 1) /* Overrun Error */
++#define LSR_DR (1 << 0) /* Data Ready */
++
++#define MCR_LOOP (1 << 4) */
++#define MCR_OUT2 (1 << 3) /* force MSR_DCD in loopback mode */
++#define MCR_OUT1 (1 << 2) /* force MSR_RI in loopback mode */
++#define MCR_RTS (1 << 1) /* Request to Send */
++#define MCR_DTR (1 << 0) /* Data Terminal Ready */
++
++#define MSR_DCD (1 << 7) /* Data Carrier Detect */
++#define MSR_RI (1 << 6) /* Ring Indicator */
++#define MSR_DSR (1 << 5) /* Data Set Ready */
++#define MSR_CTS (1 << 4) /* Clear To Send */
++#define MSR_DDCD (1 << 3) /* Delta Data Carrier Detect */
++#define MSR_TERI (1 << 2) /* Trailing Edge Ring Indicator */
++#define MSR_DDSR (1 << 1) /* Delta Data Set Ready */
++#define MSR_DCTS (1 << 0) /* Delta Clear To Send */
++
++/*
++ * IrSR (Infrared Selection Register)
++ */
++#define STISR_RXPL (1 << 4) /* Receive Data Polarity */
++#define STISR_TXPL (1 << 3) /* Transmit Data Polarity */
++#define STISR_XMODE (1 << 2) /* Transmit Pulse Width Select */
++#define STISR_RCVEIR (1 << 1) /* Receiver SIR Enable */
++#define STISR_XMITIR (1 << 0) /* Transmitter SIR Enable */
++
++
++/*
++ * I2C registers
++ */
++
++#define IBMR __REG(0x40301680) /* I2C Bus Monitor Register - IBMR */
++#define IDBR __REG(0x40301688) /* I2C Data Buffer Register - IDBR */
++#define ICR __REG(0x40301690) /* I2C Control Register - ICR */
++#define ISR __REG(0x40301698) /* I2C Status Register - ISR */
++#define ISAR __REG(0x403016A0) /* I2C Slave Address Register - ISAR */
++
++#define ICR_START (1 << 0) /* start bit */
++#define ICR_STOP (1 << 1) /* stop bit */
++#define ICR_ACKNAK (1 << 2) /* send ACK(0) or NAK(1) */
++#define ICR_TB (1 << 3) /* transfer byte bit */
++#define ICR_MA (1 << 4) /* master abort */
++#define ICR_SCLE (1 << 5) /* master clock enable */
++#define ICR_IUE (1 << 6) /* unit enable */
++#define ICR_GCD (1 << 7) /* general call disable */
++#define ICR_ITEIE (1 << 8) /* enable tx interrupts */
++#define ICR_IRFIE (1 << 9) /* enable rx interrupts */
++#define ICR_BEIE (1 << 10) /* enable bus error ints */
++#define ICR_SSDIE (1 << 11) /* slave STOP detected int enable */
++#define ICR_ALDIE (1 << 12) /* enable arbitration interrupt */
++#define ICR_SADIE (1 << 13) /* slave address detected int enable */
++#define ICR_UR (1 << 14) /* unit reset */
++
++#define ISR_RWM (1 << 0) /* read/write mode */
++#define ISR_ACKNAK (1 << 1) /* ack/nak status */
++#define ISR_UB (1 << 2) /* unit busy */
++#define ISR_IBB (1 << 3) /* bus busy */
++#define ISR_SSD (1 << 4) /* slave stop detected */
++#define ISR_ALD (1 << 5) /* arbitration loss detected */
++#define ISR_ITE (1 << 6) /* tx buffer empty */
++#define ISR_IRF (1 << 7) /* rx buffer full */
++#define ISR_GCAD (1 << 8) /* general call address detected */
++#define ISR_SAD (1 << 9) /* slave address detected */
++#define ISR_BED (1 << 10) /* bus error no ACK/NAK */
++
++
++/*
++ * Serial Audio Controller
++ */
++
++/* FIXME: This clash with SA1111 defines */
++#ifndef CONFIG_SA1111
++#define SACR0 __REG(0x40400000) /* Global Control Register */
++#define SACR1 __REG(0x40400004) /* Serial Audio I 2 S/MSB-Justified Control Register */
++#define SASR0 __REG(0x4040000C) /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */
++#define SAIMR __REG(0x40400014) /* Serial Audio Interrupt Mask Register */
++#define SAICR __REG(0x40400018) /* Serial Audio Interrupt Clear Register */
++#define SADIV __REG(0x40400060) /* Audio Clock Divider Register. */
++#define SADR __REG(0x40400080) /* Serial Audio Data Register (TX and RX FIFO access Register). */
++#endif
++
++
++/*
++ * AC97 Controller registers
++ */
++
++#define POCR __REG(0x40500000) /* PCM Out Control Register */
++#define POCR_FEIE (1 << 3) /* FIFO Error Interrupt Enable */
++
++#define PICR __REG(0x40500004) /* PCM In Control Register */
++#define PICR_FEIE (1 << 3) /* FIFO Error Interrupt Enable */
++
++#define MCCR __REG(0x40500008) /* Mic In Control Register */
++#define MCCR_FEIE (1 << 3) /* FIFO Error Interrupt Enable */
++
++#define GCR __REG(0x4050000C) /* Global Control Register */
++#define GCR_CDONE_IE (1 << 19) /* Command Done Interrupt Enable */
++#define GCR_SDONE_IE (1 << 18) /* Status Done Interrupt Enable */
++#define GCR_SECRDY_IEN (1 << 9) /* Secondary Ready Interrupt Enable */
++#define GCR_PRIRDY_IEN (1 << 8) /* Primary Ready Interrupt Enable */
++#define GCR_SECRES_IEN (1 << 5) /* Secondary Resume Interrupt Enable */
++#define GCR_PRIRES_IEN (1 << 4) /* Primary Resume Interrupt Enable */
++#define GCR_ACLINK_OFF (1 << 3) /* AC-link Shut Off */
++#define GCR_WARM_RST (1 << 2) /* AC97 Warm Reset */
++#define GCR_COLD_RST (1 << 1) /* AC'97 Cold Reset (0 = active) */
++#define GCR_GIE (1 << 0) /* Codec GPI Interrupt Enable */
++
++#define POSR __REG(0x40500010) /* PCM Out Status Register */
++#define POSR_FIFOE (1 << 4) /* FIFO error */
++
++#define PISR __REG(0x40500014) /* PCM In Status Register */
++#define PISR_FIFOE (1 << 4) /* FIFO error */
++
++#define MCSR __REG(0x40500018) /* Mic In Status Register */
++#define MCSR_FIFOE (1 << 4) /* FIFO error */
++
++#define GSR __REG(0x4050001C) /* Global Status Register */
++#define GSR_CDONE (1 << 19) /* Command Done */
++#define GSR_SDONE (1 << 18) /* Status Done */
++#define GSR_RDCS (1 << 15) /* Read Completion Status */
++#define GSR_BIT3SLT12 (1 << 14) /* Bit 3 of slot 12 */
++#define GSR_BIT2SLT12 (1 << 13) /* Bit 2 of slot 12 */
++#define GSR_BIT1SLT12 (1 << 12) /* Bit 1 of slot 12 */
++#define GSR_SECRES (1 << 11) /* Secondary Resume Interrupt */
++#define GSR_PRIRES (1 << 10) /* Primary Resume Interrupt */
++#define GSR_SCR (1 << 9) /* Secondary Codec Ready */
++#define GSR_PCR (1 << 8) /* Primary Codec Ready */
++#define GSR_MINT (1 << 7) /* Mic In Interrupt */
++#define GSR_POINT (1 << 6) /* PCM Out Interrupt */
++#define GSR_PIINT (1 << 5) /* PCM In Interrupt */
++#define GSR_MOINT (1 << 2) /* Modem Out Interrupt */
++#define GSR_MIINT (1 << 1) /* Modem In Interrupt */
++#define GSR_GSCI (1 << 0) /* Codec GPI Status Change Interrupt */
++
++#define CAR __REG(0x40500020) /* CODEC Access Register */
++#define CAR_CAIP (1 << 0) /* Codec Access In Progress */
++
++#define PCDR __REG(0x40500040) /* PCM FIFO Data Register */
++#define MCDR __REG(0x40500060) /* Mic-in FIFO Data Register */
++
++#define MOCR __REG(0x40500100) /* Modem Out Control Register */
++#define MOCR_FEIE (1 << 3) /* FIFO Error */
++
++#define MICR __REG(0x40500108) /* Modem In Control Register */
++#define MICR_FEIE (1 << 3) /* FIFO Error */
++
++#define MOSR __REG(0x40500110) /* Modem Out Status Register */
++#define MOSR_FIFOE (1 << 4) /* FIFO error */
++
++#define MISR __REG(0x40500118) /* Modem In Status Register */
++#define MISR_FIFOE (1 << 4) /* FIFO error */
++
++#define MODR __REG(0x40500140) /* Modem FIFO Data Register */
++
++#define PAC_REG_BASE __REG(0x40500200) /* Primary Audio Codec */
++#define SAC_REG_BASE __REG(0x40500300) /* Secondary Audio Codec */
++#define PMC_REG_BASE __REG(0x40500400) /* Primary Modem Codec */
++#define SMC_REG_BASE __REG(0x40500500) /* Secondary Modem Codec */
++
++
++/*
++ * USB Device Controller
++ */
++#define UDC_RES1 __REG(0x40600004) /* UDC Undocumented - Reserved1 */
++#define UDC_RES2 __REG(0x40600008) /* UDC Undocumented - Reserved2 */
++#define UDC_RES3 __REG(0x4060000C) /* UDC Undocumented - Reserved3 */
++
++#define UDCCR __REG(0x40600000) /* UDC Control Register */
++#define UDCCR_UDE (1 << 0) /* UDC enable */
++#define UDCCR_UDA (1 << 1) /* UDC active */
++#define UDCCR_RSM (1 << 2) /* Device resume */
++#define UDCCR_RESIR (1 << 3) /* Resume interrupt request */
++#define UDCCR_SUSIR (1 << 4) /* Suspend interrupt request */
++#define UDCCR_SRM (1 << 5) /* Suspend/resume interrupt mask */
++#define UDCCR_RSTIR (1 << 6) /* Reset interrupt request */
++#define UDCCR_REM (1 << 7) /* Reset interrupt mask */
++
++#define UDCCS0 __REG(0x40600010) /* UDC Endpoint 0 Control/Status Register */
++#define UDCCS0_OPR (1 << 0) /* OUT packet ready */
++#define UDCCS0_IPR (1 << 1) /* IN packet ready */
++#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */
++#define UDCCS0_DRWF (1 << 3) /* Device remote wakeup feature */
++#define UDCCS0_SST (1 << 4) /* Sent stall */
++#define UDCCS0_FST (1 << 5) /* Force stall */
++#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */
++#define UDCCS0_SA (1 << 7) /* Setup active */
++
++/* Bulk IN - Endpoint 1,6,11 */
++#define UDCCS1 __REG(0x40600014) /* UDC Endpoint 1 (IN) Control/Status Register */
++#define UDCCS6 __REG(0x40600028) /* UDC Endpoint 6 (IN) Control/Status Register */
++#define UDCCS11 __REG(0x4060003C) /* UDC Endpoint 11 (IN) Control/Status Register */
++
++#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */
++#define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */
++#define UDCCS_BI_FTF (1 << 2) /* Flush Tx FIFO */
++#define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */
++#define UDCCS_BI_SST (1 << 4) /* Sent stall */
++#define UDCCS_BI_FST (1 << 5) /* Force stall */
++#define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */
++
++/* Bulk OUT - Endpoint 2,7,12 */
++#define UDCCS2 __REG(0x40600018) /* UDC Endpoint 2 (OUT) Control/Status Register */
++#define UDCCS7 __REG(0x4060002C) /* UDC Endpoint 7 (OUT) Control/Status Register */
++#define UDCCS12 __REG(0x40600040) /* UDC Endpoint 12 (OUT) Control/Status Register */
++
++#define UDCCS_BO_RFS (1 << 0) /* Receive FIFO service */
++#define UDCCS_BO_RPC (1 << 1) /* Receive packet complete */
++#define UDCCS_BO_DME (1 << 3) /* DMA enable */
++#define UDCCS_BO_SST (1 << 4) /* Sent stall */
++#define UDCCS_BO_FST (1 << 5) /* Force stall */
++#define UDCCS_BO_RNE (1 << 6) /* Receive FIFO not empty */
++#define UDCCS_BO_RSP (1 << 7) /* Receive short packet */
++
++/* Isochronous IN - Endpoint 3,8,13 */
++#define UDCCS3 __REG(0x4060001C) /* UDC Endpoint 3 (IN) Control/Status Register */
++#define UDCCS8 __REG(0x40600030) /* UDC Endpoint 8 (IN) Control/Status Register */
++#define UDCCS13 __REG(0x40600044) /* UDC Endpoint 13 (IN) Control/Status Register */
++
++#define UDCCS_II_TFS (1 << 0) /* Transmit FIFO service */
++#define UDCCS_II_TPC (1 << 1) /* Transmit packet complete */
++#define UDCCS_II_FTF (1 << 2) /* Flush Tx FIFO */
++#define UDCCS_II_TUR (1 << 3) /* Transmit FIFO underrun */
++#define UDCCS_II_TSP (1 << 7) /* Transmit short packet */
++
++/* Isochronous OUT - Endpoint 4,9,14 */
++#define UDCCS4 __REG(0x40600020) /* UDC Endpoint 4 (OUT) Control/Status Register */
++#define UDCCS9 __REG(0x40600034) /* UDC Endpoint 9 (OUT) Control/Status Register */
++#define UDCCS14 __REG(0x40600048) /* UDC Endpoint 14 (OUT) Control/Status Register */
++
++#define UDCCS_IO_RFS (1 << 0) /* Receive FIFO service */
++#define UDCCS_IO_RPC (1 << 1) /* Receive packet complete */
++#define UDCCS_IO_ROF (1 << 3) /* Receive overflow */
++#define UDCCS_IO_DME (1 << 3) /* DMA enable */
++#define UDCCS_IO_RNE (1 << 6) /* Receive FIFO not empty */
++#define UDCCS_IO_RSP (1 << 7) /* Receive short packet */
++
++/* Interrupt IN - Endpoint 5,10,15 */
++#define UDCCS5 __REG(0x40600024) /* UDC Endpoint 5 (Interrupt) Control/Status Register */
++#define UDCCS10 __REG(0x40600038) /* UDC Endpoint 10 (Interrupt) Control/Status Register */
++#define UDCCS15 __REG(0x4060004C) /* UDC Endpoint 15 (Interrupt) Control/Status Register */
++
++#define UDCCS_INT_TFS (1 << 0) /* Transmit FIFO service */
++#define UDCCS_INT_TPC (1 << 1) /* Transmit packet complete */
++#define UDCCS_INT_FTF (1 << 2) /* Flush Tx FIFO */
++#define UDCCS_INT_TUR (1 << 3) /* Transmit FIFO underrun */
++#define UDCCS_INT_SST (1 << 4) /* Sent stall */
++#define UDCCS_INT_FST (1 << 5) /* Force stall */
++#define UDCCS_INT_TSP (1 << 7) /* Transmit short packet */
++
++#define UFNRH __REG(0x40600060) /* UDC Frame Number Register High */
++#define UFNRL __REG(0x40600064) /* UDC Frame Number Register Low */
++#define UBCR2 __REG(0x40600068) /* UDC Byte Count Reg 2 */
++#define UBCR4 __REG(0x4060006c) /* UDC Byte Count Reg 4 */
++#define UBCR7 __REG(0x40600070) /* UDC Byte Count Reg 7 */
++#define UBCR9 __REG(0x40600074) /* UDC Byte Count Reg 9 */
++#define UBCR12 __REG(0x40600078) /* UDC Byte Count Reg 12 */
++#define UBCR14 __REG(0x4060007c) /* UDC Byte Count Reg 14 */
++#define UDDR0 __REG(0x40600080) /* UDC Endpoint 0 Data Register */
++#define UDDR1 __REG(0x40600100) /* UDC Endpoint 1 Data Register */
++#define UDDR2 __REG(0x40600180) /* UDC Endpoint 2 Data Register */
++#define UDDR3 __REG(0x40600200) /* UDC Endpoint 3 Data Register */
++#define UDDR4 __REG(0x40600400) /* UDC Endpoint 4 Data Register */
++#define UDDR5 __REG(0x406000A0) /* UDC Endpoint 5 Data Register */
++#define UDDR6 __REG(0x40600600) /* UDC Endpoint 6 Data Register */
++#define UDDR7 __REG(0x40600680) /* UDC Endpoint 7 Data Register */
++#define UDDR8 __REG(0x40600700) /* UDC Endpoint 8 Data Register */
++#define UDDR9 __REG(0x40600900) /* UDC Endpoint 9 Data Register */
++#define UDDR10 __REG(0x406000C0) /* UDC Endpoint 10 Data Register */
++#define UDDR11 __REG(0x40600B00) /* UDC Endpoint 11 Data Register */
++#define UDDR12 __REG(0x40600B80) /* UDC Endpoint 12 Data Register */
++#define UDDR13 __REG(0x40600C00) /* UDC Endpoint 13 Data Register */
++#define UDDR14 __REG(0x40600E00) /* UDC Endpoint 14 Data Register */
++#define UDDR15 __REG(0x406000E0) /* UDC Endpoint 15 Data Register */
++
++#define UICR0 __REG(0x40600050) /* UDC Interrupt Control Register 0 */
++
++#define UICR0_IM0 (1 << 0) /* Interrupt mask ep 0 */
++#define UICR0_IM1 (1 << 1) /* Interrupt mask ep 1 */
++#define UICR0_IM2 (1 << 2) /* Interrupt mask ep 2 */
++#define UICR0_IM3 (1 << 3) /* Interrupt mask ep 3 */
++#define UICR0_IM4 (1 << 4) /* Interrupt mask ep 4 */
++#define UICR0_IM5 (1 << 5) /* Interrupt mask ep 5 */
++#define UICR0_IM6 (1 << 6) /* Interrupt mask ep 6 */
++#define UICR0_IM7 (1 << 7) /* Interrupt mask ep 7 */
++
++#define UICR1 __REG(0x40600054) /* UDC Interrupt Control Register 1 */
++
++#define UICR1_IM8 (1 << 0) /* Interrupt mask ep 8 */
++#define UICR1_IM9 (1 << 1) /* Interrupt mask ep 9 */
++#define UICR1_IM10 (1 << 2) /* Interrupt mask ep 10 */
++#define UICR1_IM11 (1 << 3) /* Interrupt mask ep 11 */
++#define UICR1_IM12 (1 << 4) /* Interrupt mask ep 12 */
++#define UICR1_IM13 (1 << 5) /* Interrupt mask ep 13 */
++#define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */
++#define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */
++
++#define USIR0 __REG(0x40600058) /* UDC Status Interrupt Register 0 */
++
++#define USIR0_IR0 (1 << 0) /* Interrup request ep 0 */
++#define USIR0_IR1 (1 << 1) /* Interrup request ep 1 */
++#define USIR0_IR2 (1 << 2) /* Interrup request ep 2 */
++#define USIR0_IR3 (1 << 3) /* Interrup request ep 3 */
++#define USIR0_IR4 (1 << 4) /* Interrup request ep 4 */
++#define USIR0_IR5 (1 << 5) /* Interrup request ep 5 */
++#define USIR0_IR6 (1 << 6) /* Interrup request ep 6 */
++#define USIR0_IR7 (1 << 7) /* Interrup request ep 7 */
++
++#define USIR1 __REG(0x4060005C) /* UDC Status Interrupt Register 1 */
++
++#define USIR1_IR8 (1 << 0) /* Interrup request ep 8 */
++#define USIR1_IR9 (1 << 1) /* Interrup request ep 9 */
++#define USIR1_IR10 (1 << 2) /* Interrup request ep 10 */
++#define USIR1_IR11 (1 << 3) /* Interrup request ep 11 */
++#define USIR1_IR12 (1 << 4) /* Interrup request ep 12 */
++#define USIR1_IR13 (1 << 5) /* Interrup request ep 13 */
++#define USIR1_IR14 (1 << 6) /* Interrup request ep 14 */
++#define USIR1_IR15 (1 << 7) /* Interrup request ep 15 */
++
++
++/*
++ * Fast Infrared Communication Port
++ */
++
++#define ICCR0 __REG(0x40800000) /* ICP Control Register 0 */
++#define ICCR1 __REG(0x40800004) /* ICP Control Register 1 */
++#define ICCR2 __REG(0x40800008) /* ICP Control Register 2 */
++#define ICDR __REG(0x4080000c) /* ICP Data Register */
++#define ICSR0 __REG(0x40800014) /* ICP Status Register 0 */
++#define ICSR1 __REG(0x40800018) /* ICP Status Register 1 */
++
++#define ICCR0_AME (1 << 7) /* Adress match enable */
++#define ICCR0_TIE (1 << 6) /* Transmit FIFO interrupt enable */
++#define ICCR0_RIE (1 << 5) /* Recieve FIFO interrupt enable */
++#define ICCR0_RXE (1 << 4) /* Receive enable */
++#define ICCR0_TXE (1 << 3) /* Transmit enable */
++#define ICCR0_TUS (1 << 2) /* Transmit FIFO underrun select */
++#define ICCR0_LBM (1 << 1) /* Loopback mode */
++#define ICCR0_ITR (1 << 0) /* IrDA transmission */
++
++#define ICSR0_FRE (1 << 5) /* Framing error */
++#define ICSR0_RFS (1 << 4) /* Receive FIFO service request */
++#define ICSR0_TFS (1 << 3) /* Transnit FIFO service request */
++#define ICSR0_RAB (1 << 2) /* Receiver abort */
++#define ICSR0_TUR (1 << 1) /* Trunsmit FIFO underun */
++#define ICSR0_EIF (1 << 0) /* End/Error in FIFO */
++
++#define ICSR1_ROR (1 << 6) /* Receiver FIFO underrun */
++#define ICSR1_CRE (1 << 5) /* CRC error */
++#define ICSR1_EOF (1 << 4) /* End of frame */
++#define ICSR1_TNF (1 << 3) /* Transmit FIFO not full */
++#define ICSR1_RNE (1 << 2) /* Receive FIFO not empty */
++#define ICSR1_TBY (1 << 1) /* Tramsmiter busy flag */
++#define ICSR1_RSY (1 << 0) /* Recevier synchronized flag */
++
++
++/*
++ * Real Time Clock
++ */
++
++#define RCNR __REG(0x40900000) /* RTC Count Register */
++#define RTAR __REG(0x40900004) /* RTC Alarm Register */
++#define RTSR __REG(0x40900008) /* RTC Status Register */
++#define RTTR __REG(0x4090000C) /* RTC Timer Trim Register */
++
++#define RTSR_HZE (1 << 3) /* HZ interrupt enable */
++#define RTSR_ALE (1 << 2) /* RTC alarm interrupt enable */
++#define RTSR_HZ (1 << 1) /* HZ rising-edge detected */
++#define RTSR_AL (1 << 0) /* RTC alarm detected */
++
++
++/*
++ * OS Timer & Match Registers
++ */
++
++#define OSMR0 __REG(0x40A00000) /* */
++#define OSMR1 __REG(0x40A00004) /* */
++#define OSMR2 __REG(0x40A00008) /* */
++#define OSMR3 __REG(0x40A0000C) /* */
++#define OSCR __REG(0x40A00010) /* OS Timer Counter Register */
++#define OSSR __REG(0x40A00014) /* OS Timer Status Register */
++#define OWER __REG(0x40A00018) /* OS Timer Watchdog Enable Register */
++#define OIER __REG(0x40A0001C) /* OS Timer Interrupt Enable Register */
++
++#define OSSR_M3 (1 << 3) /* Match status channel 3 */
++#define OSSR_M2 (1 << 2) /* Match status channel 2 */
++#define OSSR_M1 (1 << 1) /* Match status channel 1 */
++#define OSSR_M0 (1 << 0) /* Match status channel 0 */
++
++#define OWER_WME (1 << 0) /* Watchdog Match Enable */
++
++#define OIER_E3 (1 << 3) /* Interrupt enable channel 3 */
++#define OIER_E2 (1 << 2) /* Interrupt enable channel 2 */
++#define OIER_E1 (1 << 1) /* Interrupt enable channel 1 */
++#define OIER_E0 (1 << 0) /* Interrupt enable channel 0 */
++
++
++/*
++ * Pulse Width Modulator
++ */
++
++#define PWM_CTRL0 __REG(0x40B00000) /* PWM 0 Control Register */
++#define PWM_PWDUTY0 __REG(0x40B00004) /* PWM 0 Duty Cycle Register */
++#define PWM_PERVAL0 __REG(0x40B00008) /* PWM 0 Period Control Register */
++
++#define PWM_CTRL1 __REG(0x40C00000) /* PWM 1Control Register */
++#define PWM_PWDUTY1 __REG(0x40C00004) /* PWM 1 Duty Cycle Register */
++#define PWM_PERVAL1 __REG(0x40C00008) /* PWM 1 Period Control Register */
++
++
++/*
++ * Interrupt Controller
++ */
++
++#define ICIP __REG(0x40D00000) /* Interrupt Controller IRQ Pending Register */
++#define ICMR __REG(0x40D00004) /* Interrupt Controller Mask Register */
++#define ICLR __REG(0x40D00008) /* Interrupt Controller Level Register */
++#define ICFP __REG(0x40D0000C) /* Interrupt Controller FIQ Pending Register */
++#define ICPR __REG(0x40D00010) /* Interrupt Controller Pending Register */
++#define ICCR __REG(0x40D00014) /* Interrupt Controller Control Register */
++
++
++/*
++ * General Purpose I/O
++ */
++
++#define GPLR0 __REG(0x40E00000) /* GPIO Pin-Level Register GPIO<31:0> */
++#define GPLR1 __REG(0x40E00004) /* GPIO Pin-Level Register GPIO<63:32> */
++#define GPLR2 __REG(0x40E00008) /* GPIO Pin-Level Register GPIO<80:64> */
++
++#define GPDR0 __REG(0x40E0000C) /* GPIO Pin Direction Register GPIO<31:0> */
++#define GPDR1 __REG(0x40E00010) /* GPIO Pin Direction Register GPIO<63:32> */
++#define GPDR2 __REG(0x40E00014) /* GPIO Pin Direction Register GPIO<80:64> */
++
++#define GPSR0 __REG(0x40E00018) /* GPIO Pin Output Set Register GPIO<31:0> */
++#define GPSR1 __REG(0x40E0001C) /* GPIO Pin Output Set Register GPIO<63:32> */
++#define GPSR2 __REG(0x40E00020) /* GPIO Pin Output Set Register GPIO<80:64> */
++
++#define GPCR0 __REG(0x40E00024) /* GPIO Pin Output Clear Register GPIO<31:0> */
++#define GPCR1 __REG(0x40E00028) /* GPIO Pin Output Clear Register GPIO <63:32> */
++#define GPCR2 __REG(0x40E0002C) /* GPIO Pin Output Clear Register GPIO <80:64> */
++
++#define GRER0 __REG(0x40E00030) /* GPIO Rising-Edge Detect Register GPIO<31:0> */
++#define GRER1 __REG(0x40E00034) /* GPIO Rising-Edge Detect Register GPIO<63:32> */
++#define GRER2 __REG(0x40E00038) /* GPIO Rising-Edge Detect Register GPIO<80:64> */
++
++#define GFER0 __REG(0x40E0003C) /* GPIO Falling-Edge Detect Register GPIO<31:0> */
++#define GFER1 __REG(0x40E00040) /* GPIO Falling-Edge Detect Register GPIO<63:32> */
++#define GFER2 __REG(0x40E00044) /* GPIO Falling-Edge Detect Register GPIO<80:64> */
++
++#define GEDR0 __REG(0x40E00048) /* GPIO Edge Detect Status Register GPIO<31:0> */
++#define GEDR1 __REG(0x40E0004C) /* GPIO Edge Detect Status Register GPIO<63:32> */
++#define GEDR2 __REG(0x40E00050) /* GPIO Edge Detect Status Register GPIO<80:64> */
++
++#define GAFR0_L __REG(0x40E00054) /* GPIO Alternate Function Select Register GPIO<15:0> */
++#define GAFR0_U __REG(0x40E00058) /* GPIO Alternate Function Select Register GPIO<31:16> */
++#define GAFR1_L __REG(0x40E0005C) /* GPIO Alternate Function Select Register GPIO<47:32> */
++#define GAFR1_U __REG(0x40E00060) /* GPIO Alternate Function Select Register GPIO<63:48> */
++#define GAFR2_L __REG(0x40E00064) /* GPIO Alternate Function Select Register GPIO<79:64> */
++#define GAFR2_U __REG(0x40E00068) /* GPIO Alternate Function Select Register GPIO 80 */
++
++/* More handy macros. The argument is a literal GPIO number. */
++
++#define GPIO_bit(x) (1 << ((x) & 0x1f))
++#define GPLR(x) __REG2(0x40E00000, ((x) & 0x60) >> 3)
++#define GPDR(x) __REG2(0x40E0000C, ((x) & 0x60) >> 3)
++#define GPSR(x) __REG2(0x40E00018, ((x) & 0x60) >> 3)
++#define GPCR(x) __REG2(0x40E00024, ((x) & 0x60) >> 3)
++#define GRER(x) __REG2(0x40E00030, ((x) & 0x60) >> 3)
++#define GFER(x) __REG2(0x40E0003C, ((x) & 0x60) >> 3)
++#define GEDR(x) __REG2(0x40E00048, ((x) & 0x60) >> 3)
++#define GAFR(x) __REG2(0x40E00054, ((x) & 0x70) >> 2)
++
++/* GPIO alternate function assignments */
++
++#define GPIO1_RST 1 /* reset */
++#define GPIO6_MMCCLK 6 /* MMC Clock */
++#define GPIO8_48MHz 7 /* 48 MHz clock output */
++#define GPIO8_MMCCS0 8 /* MMC Chip Select 0 */
++#define GPIO9_MMCCS1 9 /* MMC Chip Select 1 */
++#define GPIO10_RTCCLK 10 /* real time clock (1 Hz) */
++#define GPIO11_3_6MHz 11 /* 3.6 MHz oscillator out */
++#define GPIO12_32KHz 12 /* 32 kHz out */
++#define GPIO13_MBGNT 13 /* memory controller grant */
++#define GPIO14_MBREQ 14 /* alternate bus master request */
++#define GPIO15_nCS_1 15 /* chip select 1 */
++#define GPIO16_PWM0 16 /* PWM0 output */
++#define GPIO17_PWM1 17 /* PWM1 output */
++#define GPIO18_RDY 18 /* Ext. Bus Ready */
++#define GPIO19_DREQ1 19 /* External DMA Request */
++#define GPIO20_DREQ0 20 /* External DMA Request */
++#define GPIO23_SCLK 23 /* SSP clock */
++#define GPIO24_SFRM 24 /* SSP Frame */
++#define GPIO25_STXD 25 /* SSP transmit */
++#define GPIO26_SRXD 26 /* SSP receive */
++#define GPIO27_SEXTCLK 27 /* SSP ext_clk */
++#define GPIO28_BITCLK 28 /* AC97/I2S bit_clk */
++#define GPIO29_SDATA_IN 29 /* AC97 Sdata_in0 / I2S Sdata_in */
++#define GPIO30_SDATA_OUT 30 /* AC97/I2S Sdata_out */
++#define GPIO31_SYNC 31 /* AC97/I2S sync */
++#define GPIO32_SDATA_IN1 32 /* AC97 Sdata_in1 */
++#define GPIO33_nCS_5 33 /* chip select 5 */
++#define GPIO34_FFRXD 34 /* FFUART receive */
++#define GPIO34_MMCCS0 34 /* MMC Chip Select 0 */
++#define GPIO35_FFCTS 35 /* FFUART Clear to send */
++#define GPIO36_FFDCD 36 /* FFUART Data carrier detect */
++#define GPIO37_FFDSR 37 /* FFUART data set ready */
++#define GPIO38_FFRI 38 /* FFUART Ring Indicator */
++#define GPIO39_MMCCS1 39 /* MMC Chip Select 1 */
++#define GPIO39_FFTXD 39 /* FFUART transmit data */
++#define GPIO40_FFDTR 40 /* FFUART data terminal Ready */
++#define GPIO41_FFRTS 41 /* FFUART request to send */
++#define GPIO42_BTRXD 42 /* BTUART receive data */
++#define GPIO43_BTTXD 43 /* BTUART transmit data */
++#define GPIO44_BTCTS 44 /* BTUART clear to send */
++#define GPIO45_BTRTS 45 /* BTUART request to send */
++#define GPIO46_ICPRXD 46 /* ICP receive data */
++#define GPIO46_STRXD 46 /* STD_UART receive data */
++#define GPIO47_ICPTXD 47 /* ICP transmit data */
++#define GPIO47_STTXD 47 /* STD_UART transmit data */
++#define GPIO48_nPOE 48 /* Output Enable for Card Space */
++#define GPIO49_nPWE 49 /* Write Enable for Card Space */
++#define GPIO50_nPIOR 50 /* I/O Read for Card Space */
++#define GPIO51_nPIOW 51 /* I/O Write for Card Space */
++#define GPIO52_nPCE_1 52 /* Card Enable for Card Space */
++#define GPIO53_nPCE_2 53 /* Card Enable for Card Space */
++#define GPIO53_MMCCLK 53 /* MMC Clock */
++#define GPIO54_MMCCLK 54 /* MMC Clock */
++#define GPIO54_pSKTSEL 54 /* Socket Select for Card Space */
++#define GPIO55_nPREG 55 /* Card Address bit 26 */
++#define GPIO56_nPWAIT 56 /* Wait signal for Card Space */
++#define GPIO57_nIOIS16 57 /* Bus Width select for I/O Card Space */
++#define GPIO58_LDD_0 58 /* LCD data pin 0 */
++#define GPIO59_LDD_1 59 /* LCD data pin 1 */
++#define GPIO60_LDD_2 60 /* LCD data pin 2 */
++#define GPIO61_LDD_3 61 /* LCD data pin 3 */
++#define GPIO62_LDD_4 62 /* LCD data pin 4 */
++#define GPIO63_LDD_5 63 /* LCD data pin 5 */
++#define GPIO64_LDD_6 64 /* LCD data pin 6 */
++#define GPIO65_LDD_7 65 /* LCD data pin 7 */
++#define GPIO66_LDD_8 66 /* LCD data pin 8 */
++#define GPIO66_MBREQ 66 /* alternate bus master req */
++#define GPIO67_LDD_9 67 /* LCD data pin 9 */
++#define GPIO67_MMCCS0 67 /* MMC Chip Select 0 */
++#define GPIO68_LDD_10 68 /* LCD data pin 10 */
++#define GPIO68_MMCCS1 68 /* MMC Chip Select 1 */
++#define GPIO69_LDD_11 69 /* LCD data pin 11 */
++#define GPIO69_MMCCLK 69 /* MMC_CLK */
++#define GPIO70_LDD_12 70 /* LCD data pin 12 */
++#define GPIO70_RTCCLK 70 /* Real Time clock (1 Hz) */
++#define GPIO71_LDD_13 71 /* LCD data pin 13 */
++#define GPIO71_3_6MHz 71 /* 3.6 MHz Oscillator clock */
++#define GPIO72_LDD_14 72 /* LCD data pin 14 */
++#define GPIO72_32kHz 72 /* 32 kHz clock */
++#define GPIO73_LDD_15 73 /* LCD data pin 15 */
++#define GPIO73_MBGNT 73 /* Memory controller grant */
++#define GPIO74_LCD_FCLK 74 /* LCD Frame clock */
++#define GPIO75_LCD_LCLK 75 /* LCD line clock */
++#define GPIO76_LCD_PCLK 76 /* LCD Pixel clock */
++#define GPIO77_LCD_ACBIAS 77 /* LCD AC Bias */
++#define GPIO78_nCS_2 78 /* chip select 2 */
++#define GPIO79_nCS_3 79 /* chip select 3 */
++#define GPIO80_nCS_4 80 /* chip select 4 */
++
++/* GPIO alternate function mode & direction */
++
++#define GPIO_IN 0x000
++#define GPIO_OUT 0x080
++#define GPIO_ALT_FN_1_IN 0x100
++#define GPIO_ALT_FN_1_OUT 0x180
++#define GPIO_ALT_FN_2_IN 0x200
++#define GPIO_ALT_FN_2_OUT 0x280
++#define GPIO_ALT_FN_3_IN 0x300
++#define GPIO_ALT_FN_3_OUT 0x380
++#define GPIO_MD_MASK_NR 0x07f
++#define GPIO_MD_MASK_DIR 0x080
++#define GPIO_MD_MASK_FN 0x300
++
++#define GPIO1_RTS_MD ( 1 | GPIO_ALT_FN_1_IN)
++#define GPIO6_MMCCLK_MD ( 6 | GPIO_ALT_FN_1_OUT)
++#define GPIO8_48MHz_MD ( 8 | GPIO_ALT_FN_1_OUT)
++#define GPIO8_MMCCS0_MD ( 8 | GPIO_ALT_FN_1_OUT)
++#define GPIO9_MMCCS1_MD ( 9 | GPIO_ALT_FN_1_OUT)
++#define GPIO10_RTCCLK_MD (10 | GPIO_ALT_FN_1_OUT)
++#define GPIO11_3_6MHz_MD (11 | GPIO_ALT_FN_1_OUT)
++#define GPIO12_32KHz_MD (12 | GPIO_ALT_FN_1_OUT)
++#define GPIO13_MBGNT_MD (13 | GPIO_ALT_FN_2_OUT)
++#define GPIO14_MBREQ_MD (14 | GPIO_ALT_FN_1_IN)
++#define GPIO15_nCS_1_MD (15 | GPIO_ALT_FN_2_OUT)
++#define GPIO16_PWM0_MD (16 | GPIO_ALT_FN_2_OUT)
++#define GPIO17_PWM1_MD (17 | GPIO_ALT_FN_2_OUT)
++#define GPIO18_RDY_MD (18 | GPIO_ALT_FN_1_IN)
++#define GPIO19_DREQ1_MD (19 | GPIO_ALT_FN_1_IN)
++#define GPIO20_DREQ0_MD (20 | GPIO_ALT_FN_1_IN)
++#define GPIO23_SCLK_md (23 | GPIO_ALT_FN_2_OUT)
++#define GPIO24_SFRM_MD (24 | GPIO_ALT_FN_2_OUT)
++#define GPIO25_STXD_MD (25 | GPIO_ALT_FN_2_OUT)
++#define GPIO26_SRXD_MD (26 | GPIO_ALT_FN_1_IN)
++#define GPIO27_SEXTCLK_MD (27 | GPIO_ALT_FN_1_IN)
++#define GPIO28_BITCLK_AC97_MD (28 | GPIO_ALT_FN_1_IN)
++#define GPIO28_BITCLK_I2S_MD (28 | GPIO_ALT_FN_2_IN)
++#define GPIO29_SDATA_IN_AC97_MD (29 | GPIO_ALT_FN_1_IN)
++#define GPIO29_SDATA_IN_I2S_MD (29 | GPIO_ALT_FN_2_IN)
++#define GPIO30_SDATA_OUT_AC97_MD (30 | GPIO_ALT_FN_2_OUT)
++#define GPIO30_SDATA_OUT_I2S_MD (30 | GPIO_ALT_FN_1_OUT)
++#define GPIO31_SYNC_AC97_MD (31 | GPIO_ALT_FN_2_OUT)
++#define GPIO31_SYNC_I2S_MD (31 | GPIO_ALT_FN_1_OUT)
++#define GPIO32_SDATA_IN1_AC97_MD (32 | GPIO_ALT_FN_1_IN)
++#define GPIO33_nCS_5_MD (33 | GPIO_ALT_FN_2_OUT)
++#define GPIO34_FFRXD_MD (34 | GPIO_ALT_FN_1_IN)
++#define GPIO34_MMCCS0_MD (34 | GPIO_ALT_FN_2_OUT)
++#define GPIO35_FFCTS_MD (35 | GPIO_ALT_FN_1_IN)
++#define GPIO36_FFDCD_MD (36 | GPIO_ALT_FN_1_IN)
++#define GPIO37_FFDSR_MD (37 | GPIO_ALT_FN_1_IN)
++#define GPIO38_FFRI_MD (38 | GPIO_ALT_FN_1_IN)
++#define GPIO39_MMCCS1_MD (39 | GPIO_ALT_FN_1_OUT)
++#define GPIO39_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT)
++#define GPIO40_FFDTR_MD (40 | GPIO_ALT_FN_2_OUT)
++#define GPIO41_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT)
++#define GPIO42_BTRXD_MD (42 | GPIO_ALT_FN_1_IN)
++#define GPIO43_BTTXD_MD (43 | GPIO_ALT_FN_2_OUT)
++#define GPIO44_BTCTS_MD (44 | GPIO_ALT_FN_1_IN)
++#define GPIO45_BTRTS_MD (45 | GPIO_ALT_FN_2_OUT)
++#define GPIO46_ICPRXD_MD (46 | GPIO_ALT_FN_1_IN)
++#define GPIO46_STRXD_MD (46 | GPIO_ALT_FN_2_IN)
++#define GPIO47_ICPTXD_MD (47 | GPIO_ALT_FN_2_OUT)
++#define GPIO47_STTXD_MD (47 | GPIO_ALT_FN_1_OUT)
++#define GPIO48_nPOE_MD (48 | GPIO_ALT_FN_2_OUT)
++#define GPIO49_nPWE_MD (49 | GPIO_ALT_FN_2_OUT)
++#define GPIO50_nPIOR_MD (50 | GPIO_ALT_FN_2_OUT)
++#define GPIO51_nPIOW_MD (51 | GPIO_ALT_FN_2_OUT)
++#define GPIO52_nPCE_1_MD (52 | GPIO_ALT_FN_2_OUT)
++#define GPIO53_nPCE_2_MD (53 | GPIO_ALT_FN_2_OUT)
++#define GPIO53_MMCCLK_MD (53 | GPIO_ALT_FN_1_OUT)
++#define GPIO54_MMCCLK_MD (54 | GPIO_ALT_FN_1_OUT)
++#define GPIO54_pSKTSEL_MD (54 | GPIO_ALT_FN_2_OUT)
++#define GPIO55_nPREG_MD (55 | GPIO_ALT_FN_2_OUT)
++#define GPIO56_nPWAIT_MD (56 | GPIO_ALT_FN_1_IN)
++#define GPIO57_nIOIS16_MD (57 | GPIO_ALT_FN_1_IN)
++#define GPIO58_LDD_0_MD (58 | GPIO_ALT_FN_2_OUT)
++#define GPIO59_LDD_1_MD (59 | GPIO_ALT_FN_2_OUT)
++#define GPIO60_LDD_2_MD (60 | GPIO_ALT_FN_2_OUT)
++#define GPIO61_LDD_3_MD (61 | GPIO_ALT_FN_2_OUT)
++#define GPIO62_LDD_4_MD (62 | GPIO_ALT_FN_2_OUT)
++#define GPIO63_LDD_5_MD (63 | GPIO_ALT_FN_2_OUT)
++#define GPIO64_LDD_6_MD (64 | GPIO_ALT_FN_2_OUT)
++#define GPIO65_LDD_7_MD (65 | GPIO_ALT_FN_2_OUT)
++#define GPIO66_LDD_8_MD (66 | GPIO_ALT_FN_2_OUT)
++#define GPIO66_MBREQ_MD (66 | GPIO_ALT_FN_1_IN)
++#define GPIO67_LDD_9_MD (67 | GPIO_ALT_FN_2_OUT)
++#define GPIO67_MMCCS0_MD (67 | GPIO_ALT_FN_1_OUT)
++#define GPIO68_LDD_10_MD (68 | GPIO_ALT_FN_2_OUT)
++#define GPIO68_MMCCS1_MD (68 | GPIO_ALT_FN_1_OUT)
++#define GPIO69_LDD_11_MD (69 | GPIO_ALT_FN_2_OUT)
++#define GPIO69_MMCCLK_MD (69 | GPIO_ALT_FN_1_OUT)
++#define GPIO70_LDD_12_MD (70 | GPIO_ALT_FN_2_OUT)
++#define GPIO70_RTCCLK_MD (70 | GPIO_ALT_FN_1_OUT)
++#define GPIO71_LDD_13_MD (71 | GPIO_ALT_FN_2_OUT)
++#define GPIO71_3_6MHz_MD (71 | GPIO_ALT_FN_1_OUT)
++#define GPIO72_LDD_14_MD (72 | GPIO_ALT_FN_2_OUT)
++#define GPIO72_32kHz_MD (72 | GPIO_ALT_FN_1_OUT)
++#define GPIO73_LDD_15_MD (73 | GPIO_ALT_FN_2_OUT)
++#define GPIO73_MBGNT_MD (73 | GPIO_ALT_FN_1_OUT)
++#define GPIO74_LCD_FCLK_MD (74 | GPIO_ALT_FN_2_OUT)
++#define GPIO75_LCD_LCLK_MD (75 | GPIO_ALT_FN_2_OUT)
++#define GPIO76_LCD_PCLK_MD (76 | GPIO_ALT_FN_2_OUT)
++#define GPIO77_LCD_ACBIAS_MD (77 | GPIO_ALT_FN_2_OUT)
++#define GPIO78_nCS_2_MD (78 | GPIO_ALT_FN_2_OUT)
++#define GPIO79_nCS_3_MD (79 | GPIO_ALT_FN_2_OUT)
++#define GPIO80_nCS_4_MD (80 | GPIO_ALT_FN_2_OUT)
++
++
++/*
++ * Power Manager
++ */
++
++#define PMCR __REG(0x40F00000) /* Power Manager Control Register */
++#define PSSR __REG(0x40F00004) /* Power Manager Sleep Status Register */
++#define PSPR __REG(0x40F00008) /* Power Manager Scratch Pad Register */
++#define PWER __REG(0x40F0000C) /* Power Manager Wake-up Enable Register */
++#define PRER __REG(0x40F00010) /* Power Manager GPIO Rising-Edge Detect Enable Register */
++#define PFER __REG(0x40F00014) /* Power Manager GPIO Falling-Edge Detect Enable Register */
++#define PEDR __REG(0x40F00018) /* Power Manager GPIO Edge Detect Status Register */
++#define PCFR __REG(0x40F0001C) /* Power Manager General Configuration Register */
++#define PGSR0 __REG(0x40F00020) /* Power Manager GPIO Sleep State Register for GP[31-0] */
++#define PGSR1 __REG(0x40F00024) /* Power Manager GPIO Sleep State Register for GP[63-32] */
++#define PGSR2 __REG(0x40F00028) /* Power Manager GPIO Sleep State Register for GP[84-64] */
++#define RCSR __REG(0x40F00030) /* Reset Controller Status Register */
++
++#define PSSR_RDH (1 << 5) /* Read Disable Hold */
++#define PSSR_PH (1 << 4) /* Peripheral Control Hold */
++#define PSSR_VFS (1 << 2) /* VDD Fault Status */
++#define PSSR_BFS (1 << 1) /* Battery Fault Status */
++#define PSSR_SSS (1 << 0) /* Software Sleep Status */
++
++#define PCFR_DS (1 << 3) /* Deep Sleep Mode */
++#define PCFR_FS (1 << 2) /* Float Static Chip Selects */
++#define PCFR_FP (1 << 1) /* Float PCMCIA controls */
++#define PCFR_OPDE (1 << 0) /* 3.6864 MHz oscillator power-down enable */
++
++#define RCSR_GPR (1 << 3) /* GPIO Reset */
++#define RCSR_SMR (1 << 2) /* Sleep Mode */
++#define RCSR_WDR (1 << 1) /* Watchdog Reset */
++#define RCSR_HWR (1 << 0) /* Hardware Reset */
++
++
++/*
++ * SSP Serial Port Registers
++ */
++
++#define SSCR0 __REG(0x41000000) /* SSP Control Register 0 */
++#define SSCR1 __REG(0x41000004) /* SSP Control Register 1 */
++#define SSSR __REG(0x41000008) /* SSP Status Register */
++#define SSITR __REG(0x4100000C) /* SSP Interrupt Test Register */
++#define SSDR __REG(0x41000010) /* (Write / Read) SSP Data Write Register/SSP Data Read Register */
++
++
++/*
++ * MultiMediaCard (MMC) controller
++ */
++
++#define MMC_STRPCL __REG(0x41100000) /* Control to start and stop MMC clock */
++#define MMC_STAT __REG(0x41100004) /* MMC Status Register (read only) */
++#define MMC_CLKRT __REG(0x41100008) /* MMC clock rate */
++#define MMC_SPI __REG(0x4110000c) /* SPI mode control bits */
++#define MMC_CMDAT __REG(0x41100010) /* Command/response/data sequence control */
++#define MMC_RESTO __REG(0x41100014) /* Expected response time out */
++#define MMC_RDTO __REG(0x41100018) /* Expected data read time out */
++#define MMC_BLKLEN __REG(0x4110001c) /* Block length of data transaction */
++#define MMC_NOB __REG(0x41100020) /* Number of blocks, for block mode */
++#define MMC_PRTBUF __REG(0x41100024) /* Partial MMC_TXFIFO FIFO written */
++#define MMC_I_MASK __REG(0x41100028) /* Interrupt Mask */
++#define MMC_I_REG __REG(0x4110002c) /* Interrupt Register (read only) */
++#define MMC_CMD __REG(0x41100030) /* Index of current command */
++#define MMC_ARGH __REG(0x41100034) /* MSW part of the current command argument */
++#define MMC_ARGL __REG(0x41100038) /* LSW part of the current command argument */
++#define MMC_RES __REG(0x4110003c) /* Response FIFO (read only) */
++#define MMC_RXFIFO __REG(0x41100040) /* Receive FIFO (read only) */
++#define MMC_TXFIFO __REG(0x41100044) /* Transmit FIFO (write only) */
++
++
++/*
++ * Core Clock
++ */
++
++#define CCCR __REG(0x41300000) /* Core Clock Configuration Register */
++#define CKEN __REG(0x41300004) /* Clock Enable Register */
++#define OSCC __REG(0x41300008) /* Oscillator Configuration Register */
++
++#define CCCR_N_MASK 0x0380 /* Run Mode Frequency to Turbo Mode Frequency Multiplier */
++#define CCCR_M_MASK 0x0060 /* Memory Frequency to Run Mode Frequency Multiplier */
++#define CCCR_L_MASK 0x001f /* Crystal Frequency to Memory Frequency Multiplier */
++
++#define CKEN16_LCD (1 << 16) /* LCD Unit Clock Enable */
++#define CKEN14_I2C (1 << 14) /* I2C Unit Clock Enable */
++#define CKEN13_FICP (1 << 13) /* FICP Unit Clock Enable */
++#define CKEN12_MMC (1 << 12) /* MMC Unit Clock Enable */
++#define CKEN11_USB (1 << 11) /* USB Unit Clock Enable */
++#define CKEN8_I2S (1 << 8) /* I2S Unit Clock Enable */
++#define CKEN7_BTUART (1 << 7) /* BTUART Unit Clock Enable */
++#define CKEN6_FFUART (1 << 6) /* FFUART Unit Clock Enable */
++#define CKEN5_STUART (1 << 5) /* STUART Unit Clock Enable */
++#define CKEN3_SSP (1 << 3) /* SSP Unit Clock Enable */
++#define CKEN2_AC97 (1 << 2) /* AC97 Unit Clock Enable */
++#define CKEN1_PWM1 (1 << 1) /* PWM1 Clock Enable */
++#define CKEN0_PWM0 (1 << 0) /* PWM0 Clock Enable */
++
++#define OSCC_OON (1 << 1) /* 32.768kHz OON (write-once only bit) */
++#define OSCC_OOK (1 << 0) /* 32.768kHz OOK (read-only bit) */
++
++
++/*
++ * LCD
++ */
++
++#define LCCR0 __REG(0x44000000) /* LCD Controller Control Register 0 */
++#define LCCR1 __REG(0x44000004) /* LCD Controller Control Register 1 */
++#define LCCR2 __REG(0x44000008) /* LCD Controller Control Register 2 */
++#define LCCR3 __REG(0x4400000C) /* LCD Controller Control Register 3 */
++#define DFBR0 __REG(0x44000020) /* DMA Channel 0 Frame Branch Register */
++#define DFBR1 __REG(0x44000024) /* DMA Channel 1 Frame Branch Register */
++#define LCSR __REG(0x44000038) /* LCD Controller Status Register */
++#define LIIDR __REG(0x4400003C) /* LCD Controller Interrupt ID Register */
++#define TMEDRGBR __REG(0x44000040) /* TMED RGB Seed Register */
++#define TMEDCR __REG(0x44000044) /* TMED Control Register */
++
++#define FDADR0 __REG(0x44000200) /* DMA Channel 0 Frame Descriptor Address Register */
++#define FSADR0 __REG(0x44000204) /* DMA Channel 0 Frame Source Address Register */
++#define FIDR0 __REG(0x44000208) /* DMA Channel 0 Frame ID Register */
++#define LDCMD0 __REG(0x4400020C) /* DMA Channel 0 Command Register */
++#define FDADR1 __REG(0x44000210) /* DMA Channel 1 Frame Descriptor Address Register */
++#define FSADR1 __REG(0x44000214) /* DMA Channel 1 Frame Source Address Register */
++#define FIDR1 __REG(0x44000218) /* DMA Channel 1 Frame ID Register */
++#define LDCMD1 __REG(0x4400021C) /* DMA Channel 1 Command Register */
++
++#define LCCR0_ENB (1 << 0) /* LCD Controller enable */
++#define LCCR0_CMS (1 << 1) /* Color = 0, Monochrome = 1 */
++#define LCCR0_SDS (1 << 2) /* Single Panel = 0, Dual Panel = 1 */
++#define LCCR0_LDM (1 << 3) /* LCD Disable Done Mask */
++#define LCCR0_SFM (1 << 4) /* Start of frame mask */
++#define LCCR0_IUM (1 << 5) /* Input FIFO underrun mask */
++#define LCCR0_EFM (1 << 6) /* End of Frame mask */
++#define LCCR0_PAS (1 << 7) /* Passive = 0, Active = 1 */
++#define LCCR0_BLE (1 << 8) /* Little Endian = 0, Big Endian = 1 */
++#define LCCR0_DPD (1 << 9) /* Double Pixel mode, 4 pixel value = 0, 8 pixle values = 1 */
++#define LCCR0_DIS (1 << 10) /* LCD Disable */
++#define LCCR0_QDM (1 << 11) /* LCD Quick Disable mask */
++#define LCCR0_PDD (0xff << 12) /* Palette DMA request delay */
++#define LCCR0_PDD_S 12
++#define LCCR0_BM (1 << 20) /* Branch mask */
++#define LCCR0_OUM (1 << 21) /* Output FIFO underrun mask */
++
++#define LCCR1_PPL Fld (10, 0) /* Pixels Per Line - 1 */
++#define LCCR1_DisWdth(Pixel) /* Display Width [1..800 pix.] */ \
++ (((Pixel) - 1) << FShft (LCCR1_PPL))
++
++#define LCCR1_HSW Fld (6, 10) /* Horizontal Synchronization */
++#define LCCR1_HorSnchWdth(Tpix) /* Horizontal Synchronization */ \
++ /* pulse Width [1..64 Tpix] */ \
++ (((Tpix) - 1) << FShft (LCCR1_HSW))
++
++#define LCCR1_ELW Fld (8, 16) /* End-of-Line pixel clock Wait */
++ /* count - 1 [Tpix] */
++#define LCCR1_EndLnDel(Tpix) /* End-of-Line Delay */ \
++ /* [1..256 Tpix] */ \
++ (((Tpix) - 1) << FShft (LCCR1_ELW))
++
++#define LCCR1_BLW Fld (8, 24) /* Beginning-of-Line pixel clock */
++ /* Wait count - 1 [Tpix] */
++#define LCCR1_BegLnDel(Tpix) /* Beginning-of-Line Delay */ \
++ /* [1..256 Tpix] */ \
++ (((Tpix) - 1) << FShft (LCCR1_BLW))
++
++
++#define LCCR2_LPP Fld (10, 0) /* Line Per Panel - 1 */
++#define LCCR2_DisHght(Line) /* Display Height [1..1024 lines] */ \
++ (((Line) - 1) << FShft (LCCR2_LPP))
++
++#define LCCR2_VSW Fld (6, 10) /* Vertical Synchronization pulse */
++ /* Width - 1 [Tln] (L_FCLK) */
++#define LCCR2_VrtSnchWdth(Tln) /* Vertical Synchronization pulse */ \
++ /* Width [1..64 Tln] */ \
++ (((Tln) - 1) << FShft (LCCR2_VSW))
++
++#define LCCR2_EFW Fld (8, 16) /* End-of-Frame line clock Wait */
++ /* count [Tln] */
++#define LCCR2_EndFrmDel(Tln) /* End-of-Frame Delay */ \
++ /* [0..255 Tln] */ \
++ ((Tln) << FShft (LCCR2_EFW))
++
++#define LCCR2_BFW Fld (8, 24) /* Beginning-of-Frame line clock */
++ /* Wait count [Tln] */
++#define LCCR2_BegFrmDel(Tln) /* Beginning-of-Frame Delay */ \
++ /* [0..255 Tln] */ \
++ ((Tln) << FShft (LCCR2_BFW))
++
++#if 0
++#define LCCR3_PCD (0xff) /* Pixel clock divisor */
++#define LCCR3_ACB (0xff << 8) /* AC Bias pin frequency */
++#define LCCR3_ACB_S 8
++#endif
++
++#define LCCR3_API (0xf << 16) /* AC Bias pin trasitions per interrupt */
++#define LCCR3_API_S 16
++#define LCCR3_VSP (1 << 20) /* vertical sync polarity */
++#define LCCR3_HSP (1 << 21) /* horizontal sync polarity */
++#define LCCR3_PCP (1 << 22) /* pixel clock polarity */
++#define LCCR3_OEP (1 << 23) /* output enable polarity */
++#if 0
++#define LCCR3_BPP (7 << 24) /* bits per pixel */
++#define LCCR3_BPP_S 24
++#endif
++#define LCCR3_DPC (1 << 27) /* double pixel clock mode */
++
++
++#define LCCR3_PCD Fld (8, 0) /* Pixel Clock Divisor */
++#define LCCR3_PixClkDiv(Div) /* Pixel Clock Divisor */ \
++ (((Div) << FShft (LCCR3_PCD)))
++
++
++#define LCCR3_BPP Fld (3, 24) /* Bit Per Pixel */
++#define LCCR3_Bpp(Bpp) /* Bit Per Pixel */ \
++ (((Bpp) << FShft (LCCR3_BPP)))
++
++#define LCCR3_ACB Fld (8, 8) /* AC Bias */
++#define LCCR3_Acb(Acb) /* BAC Bias */ \
++ (((Acb) << FShft (LCCR3_ACB)))
++
++#define LCCR3_HorSnchH (LCCR3_HSP*0) /* Horizontal Synchronization */
++ /* pulse active High */
++#define LCCR3_HorSnchL (LCCR3_HSP*1) /* Horizontal Synchronization */
++
++#define LCCR3_VrtSnchH (LCCR3_VSP*0) /* Vertical Synchronization pulse */
++ /* active High */
++#define LCCR3_VrtSnchL (LCCR3_VSP*1) /* Vertical Synchronization pulse */
++ /* active Low */
++
++#define LCSR_LDD (1 << 0) /* LCD Disable Done */
++#define LCSR_SOF (1 << 1) /* Start of frame */
++#define LCSR_BER (1 << 2) /* Bus error */
++#define LCSR_ABC (1 << 3) /* AC Bias count */
++#define LCSR_IUL (1 << 4) /* input FIFO underrun Lower panel */
++#define LCSR_IUU (1 << 5) /* input FIFO underrun Upper panel */
++#define LCSR_OU (1 << 6) /* output FIFO underrun */
++#define LCSR_QD (1 << 7) /* quick disable */
++#define LCSR_EOF (1 << 8) /* end of frame */
++#define LCSR_BS (1 << 9) /* branch status */
++#define LCSR_SINT (1 << 10) /* subsequent interrupt */
++
++#define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */
++
++#define LCSR_LDD (1 << 0) /* LCD Disable Done */
++#define LCSR_SOF (1 << 1) /* Start of frame */
++#define LCSR_BER (1 << 2) /* Bus error */
++#define LCSR_ABC (1 << 3) /* AC Bias count */
++#define LCSR_IUL (1 << 4) /* input FIFO underrun Lower panel */
++#define LCSR_IUU (1 << 5) /* input FIFO underrun Upper panel */
++#define LCSR_OU (1 << 6) /* output FIFO underrun */
++#define LCSR_QD (1 << 7) /* quick disable */
++#define LCSR_EOF (1 << 8) /* end of frame */
++#define LCSR_BS (1 << 9) /* branch status */
++#define LCSR_SINT (1 << 10) /* subsequent interrupt */
++
++#define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */
++
++/*
++ * Memory controller
++ */
++
++#define MDCNFG __REG(0x48000000) /* SDRAM Configuration Register 0 */
++#define MDREFR __REG(0x48000004) /* SDRAM Refresh Control Register */
++#define MSC0 __REG(0x48000008) /* Static Memory Control Register 0 */
++#define MSC1 __REG(0x4800000C) /* Static Memory Control Register 1 */
++#define MSC2 __REG(0x48000010) /* Static Memory Control Register 2 */
++#define MECR __REG(0x48000014) /* Expansion Memory (PCMCIA/Compact Flash) Bus Configuration */
++#define SXLCR __REG(0x48000018) /* LCR value to be written to SDRAM-Timing Synchronous Flash */
++#define SXCNFG __REG(0x4800001C) /* Synchronous Static Memory Control Register */
++#define SXMRS __REG(0x48000024) /* MRS value to be written to Synchronous Flash or SMROM */
++#define MCMEM0 __REG(0x48000028) /* Card interface Common Memory Space Socket 0 Timing */
++#define MCMEM1 __REG(0x4800002C) /* Card interface Common Memory Space Socket 1 Timing */
++#define MCATT0 __REG(0x48000030) /* Card interface Attribute Space Socket 0 Timing Configuration */
++#define MCATT1 __REG(0x48000034) /* Card interface Attribute Space Socket 1 Timing Configuration */
++#define MCIO0 __REG(0x48000038) /* Card interface I/O Space Socket 0 Timing Configuration */
++#define MCIO1 __REG(0x4800003C) /* Card interface I/O Space Socket 1 Timing Configuration */
++#define MDMRS __REG(0x48000040) /* MRS value to be written to SDRAM */
++#define BOOT_DEF __REG(0x48000044) /* Read-Only Boot-Time Register. Contains BOOT_SEL and PKG_SEL */
++
++#define MDREFR_K2FREE (1 << 25) /* SDRAM Free-Running Control */
++#define MDREFR_K1FREE (1 << 24) /* SDRAM Free-Running Control */
++#define MDREFR_K0FREE (1 << 23) /* SDRAM Free-Running Control */
++#define MDREFR_SLFRSH (1 << 22) /* SDRAM Self-Refresh Control/Status */
++#define MDREFR_APD (1 << 20) /* SDRAM/SSRAM Auto-Power-Down Enable */
++#define MDREFR_K2DB2 (1 << 19) /* SDCLK2 Divide by 2 Control/Status */
++#define MDREFR_K2RUN (1 << 18) /* SDCLK2 Run Control/Status */
++#define MDREFR_K1DB2 (1 << 17) /* SDCLK1 Divide by 2 Control/Status */
++#define MDREFR_K1RUN (1 << 16) /* SDCLK1 Run Control/Status */
++#define MDREFR_E1PIN (1 << 15) /* SDCKE1 Level Control/Status */
++#define MDREFR_K0DB2 (1 << 14) /* SDCLK0 Divide by 2 Control/Status */
++#define MDREFR_K0RUN (1 << 13) /* SDCLK0 Run Control/Status */
++#define MDREFR_E0PIN (1 << 12) /* SDCKE0 Level Control/Status */
++
++#endif
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/serial.h
+@@ -0,0 +1,51 @@
++/*
++ * linux/include/asm-arm/arch-pxa/serial.h
++ *
++ * Author: Nicolas Pitre
++ * Copyright: (C) 2001 MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++
++#define BAUD_BASE 921600
++
++/* Standard COM flags */
++#define STD_COM_FLAGS (ASYNC_SKIP_TEST)
++
++#define STD_SERIAL_PORT_DEFNS \
++ { \
++ type: PORT_PXA, \
++ xmit_fifo_size: 32, \
++ baud_base: BAUD_BASE, \
++ iomem_base: (void *)&FFUART,\
++ iomem_reg_shift: 2, \
++ io_type: SERIAL_IO_MEM32,\
++ irq: IRQ_FFUART, \
++ flags: STD_COM_FLAGS, \
++ }, { \
++ type: PORT_PXA, \
++ xmit_fifo_size: 32, \
++ baud_base: BAUD_BASE, \
++ iomem_base: (void *)&BTUART,\
++ iomem_reg_shift: 2, \
++ io_type: SERIAL_IO_MEM32,\
++ irq: IRQ_BTUART, \
++ flags: STD_COM_FLAGS, \
++ }, { \
++ type: PORT_PXA, \
++ xmit_fifo_size: 32, \
++ baud_base: BAUD_BASE, \
++ iomem_base: (void *)&STUART,\
++ iomem_reg_shift: 2, \
++ io_type: SERIAL_IO_MEM32,\
++ irq: IRQ_STUART, \
++ flags: STD_COM_FLAGS, \
++ }
++
++#define RS_TABLE_SIZE 8
++
++#define EXTRA_SERIAL_PORT_DEFNS
++
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/system.h
+@@ -0,0 +1,32 @@
++/*
++ * linux/include/asm-arm/arch-pxa/system.h
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "hardware.h"
++
++static inline void arch_idle(void)
++{
++ cpu_do_idle();
++}
++
++static inline void arch_reset(char mode)
++{
++ if (mode == 's') {
++ /* Jump into ROM at address 0 */
++ cpu_reset(0);
++ } else {
++ /* Initialize the watchdog and let it fire */
++ OWER = OWER_WME;
++ OSSR = OSSR_M3;
++ OSMR3 = OSCR + 368640; /* ... in 100 ms */
++ }
++}
++
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/time.h
+@@ -0,0 +1,86 @@
++/*
++ * linux/include/asm-arm/arch-pxa/time.h
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++
++static inline unsigned long pxa_get_rtc_time(void)
++{
++ return RCNR;
++}
++
++static int pxa_set_rtc(void)
++{
++ unsigned long current_time = xtime.tv_sec;
++
++ if (RTSR & RTSR_ALE) {
++ /* make sure not to forward the clock over an alarm */
++ unsigned long alarm = RTAR;
++ if (current_time >= alarm && alarm >= RCNR)
++ return -ERESTARTSYS;
++ }
++ RCNR = current_time;
++ return 0;
++}
++
++/* IRQs are disabled before entering here from do_gettimeofday() */
++static unsigned long pxa_gettimeoffset (void)
++{
++ unsigned long ticks_to_match, elapsed, usec;
++
++ /* Get ticks before next timer match */
++ ticks_to_match = OSMR0 - OSCR;
++
++ /* We need elapsed ticks since last match */
++ elapsed = LATCH - ticks_to_match;
++
++ /* Now convert them to usec */
++ usec = (unsigned long)(elapsed*tick)/LATCH;
++
++ return usec;
++}
++
++static void pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ long flags;
++ int next_match;
++
++ do_profile(regs);
++
++ /* Loop until we get ahead of the free running timer.
++ * This ensures an exact clock tick count and time acuracy.
++ * IRQs are disabled inside the loop to ensure coherence between
++ * lost_ticks (updated in do_timer()) and the match reg value, so we
++ * can use do_gettimeofday() from interrupt handlers.
++ */
++ do {
++ do_leds();
++ do_set_rtc();
++ save_flags_cli( flags );
++ do_timer(regs);
++ OSSR = OSSR_M0; /* Clear match on timer 0 */
++ next_match = (OSMR0 += LATCH);
++ restore_flags( flags );
++ } while( (signed long)(next_match - OSCR) <= 0 );
++}
++
++extern inline void setup_timer (void)
++{
++ gettimeoffset = pxa_gettimeoffset;
++ set_rtc = pxa_set_rtc;
++ xtime.tv_sec = pxa_get_rtc_time();
++ timer_irq.handler = pxa_timer_interrupt;
++ OSMR0 = 0; /* set initial match at 0 */
++ OSSR = 0xf; /* clear status on all timers */
++ setup_arm_irq(IRQ_OST0, &timer_irq);
++ OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */
++ OSCR = 0; /* initialize free-running timer, force first match */
++}
++
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/timex.h
+@@ -0,0 +1,17 @@
++/*
++ * linux/include/asm-arm/arch-pxa/timex.h
++ *
++ * Author: Nicolas Pitre
++ * Created: Jun 15, 2001
++ * Copyright: MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * PXA250/210 timer
++ */
++#define CLOCK_TICK_RATE 3686400
++#define CLOCK_TICK_FACTOR 80
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/trizeps2.h
+@@ -0,0 +1,206 @@
++/*
++ * linux/include/asm-arm/arch-pxa/trizeps2.h
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Copyright (c) 2002 Luc De Cock, Teradyne DS, Ltd.
++ *
++ * 2002-10-10: Initial code started from idp.h
++ */
++
++
++/*
++ * Note: this file must be safe to include in assembly files
++ */
++
++/* comment out following if you have a board with 32MB RAM */
++//#define PXA_TRIZEPS2_64MB 1
++#undef PXA_TRIZEPS2_64MB
++
++#define TRIZEPS2_FLASH_PHYS (PXA_CS0_PHYS)
++#define TRIZEPS2_ALT_FLASH_PHYS (PXA_CS1_PHYS)
++#define TRIZEPS2_MEDIAQ_PHYS (PXA_CS3_PHYS)
++#define TRIZEPS2_IDE_PHYS (PXA_CS5_PHYS + 0x03000000)
++#define TRIZEPS2_ETH_PHYS (0x0C800000)
++#define TRIZEPS2_COREVOLT_PHYS (PXA_CS5_PHYS + 0x03800000)
++#define TRIZEPS2_BCR_PHYS (0x0E000000)
++#define TRIZEPS2_CPLD_PHYS (0x0C000000)
++
++/*
++ * virtual memory map
++ */
++
++#define TRIZEPS2_IDE_BASE (0xf0000000)
++#define TRIZEPS2_IDE_SIZE (1*1024*1024)
++
++#define TRIZEPS2_ETH_BASE (0xf1000000)
++#define TRIZEPS2_ETH_SIZE (1*1024*1024)
++#define ETH_BASE TRIZEPS2_ETH_BASE //smc9194 driver compatibility issue
++
++#define TRIZEPS2_COREVOLT_BASE (TRIZEPS2_ETH_BASE + TRIZEPS2_ETH_SIZE)
++#define TRIZEPS2_COREVOLT_SIZE (1*1024*1024)
++
++#define TRIZEPS2_BCR_BASE (0xf0000000)
++#define TRIZEPS2_BCR_SIZE (1*1024*1024)
++
++#define BCR_P2V(x) ((x) - TRIZEPS2_BCR_PHYS + TRIZEPS2_BCR_BASE)
++#define BCR_V2P(x) ((x) - TRIZEPS2_BCR_BASE + TRIZEPS2_BCR_PHYS)
++
++#ifndef __ASSEMBLY__
++# define __BCR_REG(x) (*((volatile unsigned short *)BCR_P2V(x)))
++#else
++# define __BCR_REG(x) BCR_P2V(x)
++#endif
++
++/* board level registers */
++#define TRIZEPS2_CPLD_BASE (0xf0100000)
++#define CPLD_P2V(x) ((x) - TRIZEPS2_CPLD_PHYS + TRIZEPS2_CPLD_BASE)
++#define CPLD_V2P(x) ((x) - TRIZEPS2_CPLD_BASE + TRIZEPS2_CPLD_PHYS)
++
++#ifndef __ASSEMBLY__
++# define __CPLD_REG(x) (*((volatile unsigned short *)CPLD_P2V(x)))
++#else
++# define __CPLD_REG(x) CPLD_P2V(x)
++#endif
++
++#define _TRIZEPS2_PCCARD_STATUS (0x0c000000)
++#define TRIZEPS2_PCCARD_STATUS __CPLD_REG(_TRIZEPS2_PCCARD_STATUS)
++
++/*
++ * CS memory timing via Static Memory Control Register (MSC0-2)
++ */
++
++#define MSC_CS(cs,val) ((val)<<((cs&1)<<4))
++
++#define MSC_RBUFF_SHIFT 15
++#define MSC_RBUFF(x) ((x)<<MSC_RBUFF_SHIFT)
++#define MSC_RBUFF_SLOW MSC_RBUFF(0)
++#define MSC_RBUFF_FAST MSC_RBUFF(1)
++
++#define MSC_RRR_SHIFT 12
++#define MSC_RRR(x) ((x)<<MSC_RRR_SHIFT)
++
++#define MSC_RDN_SHIFT 8
++#define MSC_RDN(x) ((x)<<MSC_RDN_SHIFT)
++
++#define MSC_RDF_SHIFT 4
++#define MSC_RDF(x) ((x)<<MSC_RDF_SHIFT)
++
++#define MSC_RBW_SHIFT 3
++#define MSC_RBW(x) ((x)<<MSC_RBW_SHIFT)
++#define MSC_RBW_16 MSC_RBW(1)
++#define MSC_RBW_32 MSC_RBW(0)
++
++#define MSC_RT_SHIFT 0
++#define MSC_RT(x) ((x)<<MSC_RT_SHIFT)
++
++
++/*
++ * Bit masks for various registers
++ */
++// TRIZEPS2_BCR_PCCARD_PWR
++#define PCC_3V (1 << 0)
++#define PCC_5V (1 << 1)
++#define PCC_EN1 (1 << 2)
++#define PCC_EN0 (1 << 3)
++
++// TRIZEPS2_BCR_PCCARD_EN
++#define PCC_RESET (1 << 6)
++#define PCC_ENABLE (1 << 0)
++
++// TRIZEPS2_BSR_PCCARDx_STATUS
++#define _PCC_WRPROT (1 << 7) // 7-4 read as low true
++#define _PCC_RESET (1 << 6)
++#define _PCC_IRQ (1 << 5)
++#define _PCC_INPACK (1 << 4)
++#define PCC_BVD1 (1 << 0)
++#define PCC_BVD2 (1 << 1)
++#define PCC_VS1 (1 << 2)
++#define PCC_VS2 (1 << 3)
++
++// TRIZEPS2_BCR_CONTROL bits
++#define BCR_LCD_ON (1 << 4)
++#define BCR_LCD_OFF (0)
++#define BCR_LCD_MASK (1 << 4)
++#define BCR_PCMCIA_RESET (1 << 7)
++#define BCR_PCMCIA_NORMAL (0)
++
++#define PCC_DETECT (GPLR(24) & GPIO_bit(24))
++#define PCC_READY (GPLR(1) & GPIO_bit(1))
++
++// Board Control Register
++#define _TRIZEPS2_BCR_CONTROL (TRIZEPS2_BCR_PHYS)
++#define TRIZEPS2_BCR_CONTROL __BCR_REG(_TRIZEPS2_BCR_CONTROL)
++
++// Board TTL-IO register
++#define TRIZEPS2_TTLIO_PHYS (0x0d800000)
++#define TRIZEPS2_TTLIO_BASE (0xf2000000)
++// various ioctl cmds
++#define TTLIO_RESET 0
++#define TTLIO_GET 1
++#define TTLIO_SET 2
++#define TTLIO_UNSET 3
++
++/*
++ * Macros for LCD Driver
++ */
++
++#ifdef CONFIG_FB_PXA
++
++#define FB_BACKLIGHT_ON()
++#define FB_BACKLIGHT_OFF()
++
++#define FB_PWR_ON()
++#define FB_PWR_OFF()
++
++#define FB_VLCD_ON() WRITE_TRIZEPS2_BCR(BCR_LCD_ON,BCR_LCD_MASK);
++#define FB_VLCD_OFF() WRITE_TRIZEPS2_BCR(BCR_LCD_OFF,BCR_LCD_MASK);
++
++#endif
++
++/* A listing of interrupts used by external hardware devices */
++
++#define GPIO_TOUCH_PANEL_IRQ 2
++#define TOUCH_PANEL_IRQ IRQ_GPIO(GPIO_TOUCH_PANEL_IRQ)
++#define GPIO_ETHERNET_IRQ 19
++#define ETHERNET_IRQ IRQ_GPIO(GPIO_ETHERNET_IRQ)
++#define GPIO_TTLIO_IRQ 23
++#define TTLIO_IRQ IRQ_GPIO(GPIO_TTLIO_IRQ)
++
++#define TOUCH_PANEL_IRQ_EDGE GPIO_FALLING_EDGE
++#define IDE_IRQ_EDGE GPIO_RISING_EDGE
++#define ETHERNET_IRQ_EDGE GPIO_RISING_EDGE
++
++#define PCMCIA_S_CD_VALID IRQ_GPIO(24)
++#define PCMCIA_S_CD_VALID_EDGE GPIO_BOTH_EDGES
++
++#define PCMCIA_S_RDYINT IRQ_GPIO(1)
++#define PCMCIA_S_RDYINT_EDGE GPIO_FALLING_EDGE
++
++/*
++ * macros for MTD driver
++ */
++
++#define FLASH_WRITE_PROTECT_DISABLE() // ((TRIZEPS2_CPLD_FLASH_WE) &= ~(0x1))
++#define FLASH_WRITE_PROTECT_ENABLE() // ((TRIZEPS2_CPLD_FLASH_WE) |= (0x1))
++
++/* shadow registers for write only registers */
++#ifndef __ASSEMBLY__
++extern unsigned short trizeps2_bcr_shadow;
++#endif
++
++/*
++ * macros to write to write only register
++ *
++ * none of these macros are protected from
++ * multiple drivers using them in interrupt context.
++ */
++
++#define WRITE_TRIZEPS2_BCR(value, mask) \
++{\
++ trizeps2_bcr_shadow = ((value & mask) | (trizeps2_bcr_shadow & ~mask));\
++ TRIZEPS2_BCR_CONTROL = trizeps2_bcr_shadow;\
++}
++
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/uncompress.h
+@@ -0,0 +1,42 @@
++/*
++ * linux/include/asm-arm/arch-pxa/uncompress.h
++ *
++ * Author: Nicolas Pitre
++ * Copyright: (C) 2001 MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#define FFUART ((volatile unsigned long *)0x40100000)
++#define BTUART ((volatile unsigned long *)0x40200000)
++#define STUART ((volatile unsigned long *)0x40700000)
++
++#define UART FFUART
++
++
++static __inline__ void putc(char c)
++{
++ while (!(UART[5] & 0x20));
++ UART[0] = c;
++}
++
++/*
++ * This does not append a newline
++ */
++static void puts(const char *s)
++{
++ while (*s) {
++ putc(*s);
++ if (*s == '\n')
++ putc('\r');
++ s++;
++ }
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_setup()
++#define arch_decomp_wdog()
+--- /dev/null
++++ linux-2.4.27/include/asm-arm/arch-pxa/vmalloc.h
+@@ -0,0 +1,23 @@
++/*
++ * linux/include/asm-arm/arch-pxa/vmalloc.h
++ *
++ * Author: Nicolas Pitre
++ * Copyright: (C) 2001 MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * Just any arbitrary offset to the start of the vmalloc VM area: the
++ * current 8MB value just means that there will be a 8MB "hole" after the
++ * physical memory until the kernel virtual memory starts. That means that
++ * any out-of-bounds memory accesses will hopefully be caught.
++ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
++ * area for the same reason. ;)
++ */
++#define VMALLOC_OFFSET (8*1024*1024)
++#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
++#define VMALLOC_VMADDR(x) ((unsigned long)(x))
++#define VMALLOC_END (0xe8000000)
+--- linux-2.4.27/include/asm-arm/assembler.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/asm-arm/assembler.h
+@@ -13,3 +13,26 @@
+
+ #include <asm/proc/ptrace.h>
+ #include <asm/proc/assembler.h>
++
++/*
++ * Endian independent macros for shifting bytes within registers.
++ */
++#ifndef __ARMEB__
++#define pull lsr
++#define push lsl
++#define byte(x) (x*8)
++#else
++#define pull lsl
++#define push lsr
++#define byte(x) ((3-x)*8)
++#endif
++
++/*
++ * Data preload for architectures that support it
++ */
++#if __LINUX_ARM_ARCH__ >= 5
++#define PLD(code...) code
++#else
++#define PLD(code...)
++#endif
++
+--- linux-2.4.27/include/asm-arm/bitops.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/asm-arm/bitops.h
+@@ -91,6 +91,8 @@
+ return (((unsigned char *) addr)[nr >> 3] >> (nr & 7)) & 1;
+ }
+
++#if __LINUX_ARM_ARCH__ < 5
++
+ /*
+ * ffz = Find First Zero in word. Undefined if no zero exists,
+ * so code should check against ~0UL first..
+@@ -117,6 +119,23 @@
+
+ #define ffs(x) generic_ffs(x)
+
++#else
++
++/*
++ * On ARMv5 and above those functions can be implemented around
++ * the clz instruction for much better code efficiency.
++ */
++
++extern __inline__ int generic_fls(int x);
++#define fls(x) \
++ ( __builtin_constant_p(x) ? generic_fls(x) : \
++ ({ int __r; asm("clz%?\t%0, %1" : "=r"(__r) : "r"(x)); 32-__r; }) )
++#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); })
++#define __ffs(x) (ffs(x) - 1)
++#define ffz(x) __ffs( ~(x) )
++
++#endif
++
+ /*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+--- linux-2.4.27/include/asm-arm/io.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/asm-arm/io.h
+@@ -168,7 +168,7 @@
+ * devices. This is the "generic" version. The PCI specific version
+ * is in pci.h
+ */
+-extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle);
++extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, unsigned long flags);
+ extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle);
+ extern void consistent_sync(void *vaddr, size_t size, int rw);
+
+--- linux-2.4.27/include/asm-arm/memory.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/asm-arm/memory.h
+@@ -123,6 +123,9 @@
+ ((unsigned)((page) - NODE_MEM_MAP(node)) < NODE_DATA(node)->node_size)); \
+ })
+
++/* We want large page mapping possible */
++#define VMALLOC_ALIGN 0x10000
++
+ #endif
+
+ /*
+--- linux-2.4.27/include/asm-arm/proc-armv/pgtable.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/asm-arm/proc-armv/pgtable.h
+@@ -15,9 +15,6 @@
+ #ifndef __ASM_PROC_PGTABLE_H
+ #define __ASM_PROC_PGTABLE_H
+
+-#include <asm/proc/domain.h>
+-#include <asm/arch/vmalloc.h>
+-
+ /*
+ * entries per page directory level: they are two-level, so
+ * we don't really have any PMD directory.
+@@ -26,27 +23,92 @@
+ #define PTRS_PER_PMD 1
+ #define PTRS_PER_PGD 4096
+
+-/****************
+-* PMD functions *
+-****************/
+-
+-/* PMD types (actually level 1 descriptor) */
+-#define PMD_TYPE_MASK 0x0003
+-#define PMD_TYPE_FAULT 0x0000
+-#define PMD_TYPE_TABLE 0x0001
+-#define PMD_TYPE_SECT 0x0002
+-#define PMD_UPDATABLE 0x0010
+-#define PMD_SECT_CACHEABLE 0x0008
+-#define PMD_SECT_BUFFERABLE 0x0004
+-#define PMD_SECT_AP_WRITE 0x0400
+-#define PMD_SECT_AP_READ 0x0800
++/*
++ * Hardware page table definitions.
++ *
++ * + Level 1 descriptor (PMD)
++ * - common
++ */
++#define PMD_TYPE_MASK (3 << 0)
++#define PMD_TYPE_FAULT (0 << 0)
++#define PMD_TYPE_TABLE (1 << 0)
++#define PMD_TYPE_SECT (2 << 0)
++#define PMD_UPDATABLE (1 << 4)
+ #define PMD_DOMAIN(x) ((x) << 5)
++#define PMD_PROTECTION (1 << 9) /* v5 */
++/*
++ * - section
++ */
++#define PMD_SECT_BUFFERABLE (1 << 2)
++#define PMD_SECT_CACHEABLE (1 << 3)
++#define PMD_SECT_AP_WRITE (1 << 10)
++#define PMD_SECT_AP_READ (1 << 11)
++#define PMD_SECT_TEX(x) ((x) << 12) /* v5 */
++/*
++ * - coarse table
++ */
++
++/*
++ * + Level 2 descriptor (PTE)
++ * - common
++ */
++#define PTE_TYPE_MASK (3 << 0)
++#define PTE_TYPE_FAULT (0 << 0)
++#define PTE_TYPE_LARGE (1 << 0)
++#define PTE_TYPE_SMALL (2 << 0)
++#define PTE_TYPE_EXT (3 << 0) /* v5 */
++#define PTE_BUFFERABLE (1 << 2)
++#define PTE_CACHEABLE (1 << 3)
++
++/*
++ * - extended small page/tiny page
++ */
++#define PTE_EXT_AP_UNO_SRO (0 << 4)
++#define PTE_EXT_AP_UNO_SRW (1 << 4)
++#define PTE_EXT_AP_URO_SRW (2 << 4)
++#define PTE_EXT_AP_URW_SRW (3 << 4)
++#define PTE_EXT_TEX(x) ((x) << 6) /* v5 */
++
++/*
++ * - small page
++ */
++#define PTE_SMALL_AP_UNO_SRO (0x00 << 4)
++#define PTE_SMALL_AP_UNO_SRW (0x55 << 4)
++#define PTE_SMALL_AP_URO_SRW (0xaa << 4)
++#define PTE_SMALL_AP_URW_SRW (0xff << 4)
++#define PTE_AP_READ PTE_SMALL_AP_URO_SRW
++#define PTE_AP_WRITE PTE_SMALL_AP_UNO_SRW
++
++/*
++ * "Linux" PTE definitions.
++ *
++ * We keep two sets of PTEs - the hardware and the linux version.
++ * This allows greater flexibility in the way we map the Linux bits
++ * onto the hardware tables, and allows us to have YOUNG and DIRTY
++ * bits.
++ *
++ * The PTE table pointer refers to the hardware entries; the "Linux"
++ * entries are stored 1024 bytes below.
++ */
++#define L_PTE_PRESENT (1 << 0)
++#define L_PTE_YOUNG (1 << 1)
++#define L_PTE_BUFFERABLE (1 << 2) /* matches PTE */
++#define L_PTE_CACHEABLE (1 << 3) /* matches PTE */
++#define L_PTE_USER (1 << 4)
++#define L_PTE_WRITE (1 << 5)
++#define L_PTE_EXEC (1 << 6)
++#define L_PTE_DIRTY (1 << 7)
++
++#ifndef __ASSEMBLY__
++
++#include <asm/proc/domain.h>
++#include <asm/arch/vmalloc.h>
+
+ #define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER))
+ #define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL))
+
+ #define pmd_bad(pmd) (pmd_val(pmd) & 2)
+-#define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp,pmd)
++#define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp, pmd)
+
+ static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot)
+ {
+@@ -75,49 +137,8 @@
+ return __phys_to_virt(ptr);
+ }
+
+-/****************
+-* PTE functions *
+-****************/
+-
+-/* PTE types (actually level 2 descriptor) */
+-#define PTE_TYPE_MASK 0x0003
+-#define PTE_TYPE_FAULT 0x0000
+-#define PTE_TYPE_LARGE 0x0001
+-#define PTE_TYPE_SMALL 0x0002
+-#define PTE_AP_READ 0x0aa0
+-#define PTE_AP_WRITE 0x0550
+-#define PTE_CACHEABLE 0x0008
+-#define PTE_BUFFERABLE 0x0004
+-
+ #define set_pte(ptep, pte) cpu_set_pte(ptep,pte)
+
+-/* We now keep two sets of ptes - the physical and the linux version.
+- * This gives us many advantages, and allows us greater flexibility.
+- *
+- * The Linux pte's contain:
+- * bit meaning
+- * 0 page present
+- * 1 young
+- * 2 bufferable - matches physical pte
+- * 3 cacheable - matches physical pte
+- * 4 user
+- * 5 write
+- * 6 execute
+- * 7 dirty
+- * 8-11 unused
+- * 12-31 virtual page address
+- *
+- * These are stored at the pte pointer; the physical PTE is at -1024bytes
+- */
+-#define L_PTE_PRESENT (1 << 0)
+-#define L_PTE_YOUNG (1 << 1)
+-#define L_PTE_BUFFERABLE (1 << 2)
+-#define L_PTE_CACHEABLE (1 << 3)
+-#define L_PTE_USER (1 << 4)
+-#define L_PTE_WRITE (1 << 5)
+-#define L_PTE_EXEC (1 << 6)
+-#define L_PTE_DIRTY (1 << 7)
+-
+ /*
+ * The following macros handle the cache and bufferable bits...
+ */
+@@ -162,5 +183,8 @@
+ * Mark the prot value as uncacheable and unbufferable.
+ */
+ #define pgprot_noncached(prot) __pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE))
++#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~L_PTE_CACHEABLE)
++
++#endif /* __ASSEMBLY__ */
+
+ #endif /* __ASM_PROC_PGTABLE_H */
+--- linux-2.4.27/include/asm-arm/proc-armv/processor.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/asm-arm/proc-armv/processor.h
+@@ -23,6 +23,9 @@
+ #define KERNEL_STACK_SIZE PAGE_SIZE
+
+ struct context_save_struct {
++#ifdef CONFIG_CPU_XSCALE
++ long long acc0;
++#endif
+ unsigned long cpsr;
+ unsigned long r4;
+ unsigned long r5;
+@@ -35,7 +38,11 @@
+ unsigned long pc;
+ };
+
++#ifdef CONFIG_CPU_XSCALE
++#define INIT_CSS (struct context_save_struct){ 0, SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
++#else
+ #define INIT_CSS (struct context_save_struct){ SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
++#endif
+
+ #define EXTRA_THREAD_STRUCT \
+ unsigned int domain;
+--- linux-2.4.27/include/asm-arm/proc-fns.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/asm-arm/proc-fns.h
+@@ -124,6 +124,14 @@
+ # define CPU_NAME sa1100
+ # endif
+ # endif
++# ifdef CONFIG_CPU_XSCALE
++# ifdef CPU_NAME
++# undef MULTI_CPU
++# define MULTI_CPU
++# else
++# define CPU_NAME xscale
++# endif
++# endif
+ #endif
+
+ #ifndef MULTI_CPU
+--- linux-2.4.27/include/asm-arm/procinfo.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/asm-arm/procinfo.h
+@@ -55,7 +55,8 @@
+ #define HWCAP_FAST_MULT 16
+ #define HWCAP_FPA 32
+ #define HWCAP_VFP 64
+-#define HWCAP_EDSP 128
++#define HWCAP_EDSP 128 /* El Segundo */
+ #define HWCAP_JAVA 256
++#define HWCAP_XSCALE 512 /* XScale DSP co-processor */
+
+ #endif
+--- linux-2.4.27/include/asm-arm/uaccess.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/asm-arm/uaccess.h
+@@ -86,7 +86,7 @@
+ __get_user_x(__r1, __p, __e, 1, "lr"); \
+ break; \
+ case 2: \
+- __get_user_x(__r1, __p, __e, 2, "r2", "lr"); \
++ __get_user_x(__r1, __p, __e, 2, "ip", "lr"); \
+ break; \
+ case 4: \
+ __get_user_x(__r1, __p, __e, 4, "lr"); \
+--- linux-2.4.27/include/linux/cramfs_fs_sb.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/linux/cramfs_fs_sb.h
+@@ -10,6 +10,10 @@
+ unsigned long blocks;
+ unsigned long files;
+ unsigned long flags;
++#ifdef CONFIG_CRAMFS_LINEAR
++ unsigned long linear_phys_addr;
++ char * linear_virt_addr;
++#endif
+ };
+
+ #endif
+--- linux-2.4.27/include/linux/i2c-id.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/linux/i2c-id.h
+@@ -100,6 +100,10 @@
+ #define I2C_DRIVERID_SAA7191 57 /* video decoder */
+ #define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */
+
++#define I2C_DRIVERID_DS1307 46 /* real time clock: DS1307 */
++#define I2C_DRIVERID_24LC64 47 /* EEprom 24LC64 */
++#define I2C_DRIVERID_FM24CLB4 48 /* EEprom FM24CLB4 */
++
+ #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */
+ #define I2C_DRIVERID_EXP1 0xF1
+ #define I2C_DRIVERID_EXP2 0xF2
+@@ -172,6 +176,8 @@
+
+ #define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */
+
++#define I2C_ALGO_PXA 0x400000 /* Intel PXA I2C algorithm */
++
+ #define I2C_ALGO_EXP 0x800000 /* experimental */
+
+ #define I2C_ALGO_MASK 0xff0000 /* Mask for algorithms */
+--- linux-2.4.27/include/linux/serial.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/linux/serial.h
+@@ -75,11 +75,13 @@
+ #define PORT_16654 11
+ #define PORT_16850 12
+ #define PORT_RSA 13 /* RSA-DV II/S card */
+-#define PORT_MAX 13
++#define PORT_PXA 14
++#define PORT_MAX 14
+
+ #define SERIAL_IO_PORT 0
+ #define SERIAL_IO_HUB6 1
+ #define SERIAL_IO_MEM 2
++#define SERIAL_IO_MEM32 3
+
+ struct serial_uart_config {
+ char *name;
+--- linux-2.4.27/include/linux/serial_reg.h~2.4.27-vrs1-pxa1
++++ linux-2.4.27/include/linux/serial_reg.h
+@@ -119,6 +119,14 @@
+ #define UART_IERX_SLEEP 0x10 /* Enable sleep mode */
+
+ /*
++ * The Intel PXA250/210 chip defines those bits
++ */
++#define UART_IER_DMAE 0x80 /* DMA Requests Enable */
++#define UART_IER_UUE 0x40 /* UART Unit Enable */
++#define UART_IER_NRZE 0x20 /* NRZ coding Enable */
++#define UART_IER_RTOIE 0x10 /* Receiver Time Out Interrupt Enable */
++
++/*
+ * These are the definitions for the Modem Control Register
+ */
+ #define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS (TI16C750) */
+--- /dev/null
++++ linux-2.4.27/include/mmc/ioctl.h
+@@ -0,0 +1,25 @@
++/*
++ * linux/include/linux/mmc/ioctl.h
++ *
++ * Author: Vladimir Shebordaev
++ * Copyright: MontaVista Software Inc.
++ *
++ * $Id: ioctl.h,v 0.2 2002/07/11 16:28:21 ted Exp ted $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef __MMC_IOCTL_H__
++#define __MMC_IOCTL_H__
++
++#include <asm/ioctl.h>
++
++/* IOCTL commands provided by MMC subsystem */
++#define IOCMMCSTRNSMODE _IOW('I',0x0f01,int)
++#define IOCMMCGTRNSMODE _IOR('I',0x0f02,int)
++#define IOCMMCGCARDESC _IOR('I',0x0f03,int) /* FIXME */
++#define IOCMMCGBLKSZMAX _IOR('I',0x0f04,ssize_t)
++#define IOCMMCGNOBMAX _IOR('I',0x0f05,ssize_t)
++
++#endif /* __MMC_IOCTL_H__ */
+--- /dev/null
++++ linux-2.4.27/include/mmc/mmc.h
+@@ -0,0 +1,143 @@
++/*
++ * linux/include/linux/mmc/mmc.h
++ *
++ * Author: Vladimir Shebordaev
++ * Copyright: MontaVista Software Inc.
++ *
++ * $Id: mmc.h,v 0.2.1.2 2002/07/25 16:29:47 ted Exp ted $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef __MMC_H__
++#define __MMC_H__
++
++#include <linux/types.h>
++#include <mmc/types.h>
++
++/*
++ * MMC card type
++ */
++enum _mmc_type {
++ MMC_CARD_TYPE_RO = 1,
++ MMC_CARD_TYPE_RW,
++ MMC_CARD_TYPE_IO
++};
++
++/*
++ * MMC card state
++ */
++enum _mmc_state {
++ MMC_CARD_STATE_IDLE = 1,
++ MMC_CARD_STATE_READY,
++ MMC_CARD_STATE_IDENT,
++ MMC_CARD_STATE_STNBY,
++ MMC_CARD_STATE_TRAN,
++ MMC_CARD_STATE_DATA,
++ MMC_CARD_STATE_RCV,
++ MMC_CARD_STATE_DIS,
++ MMC_CARD_STATE_UNPLUGGED=0xff
++};
++
++/*
++ * Data transfer mode
++ */
++enum _mmc_transfer_mode {
++ MMC_TRANSFER_MODE_STREAM = 1,
++ MMC_TRANSFER_MODE_BLOCK_SINGLE,
++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE,
++ MMC_TRANSFER_MODE_UNDEFINED = -1
++};
++
++struct _mmc_card_csd_rec { /* CSD register contents */
++/* FIXME: BYTE_ORDER */
++ u8 ecc:2,
++ file_format:2,
++ tmp_write_protect:1,
++ perm_write_protect:1,
++ copy:1,
++ file_format_grp:1;
++ u64 content_prot_app:1,
++ rsvd3:4,
++ write_bl_partial:1,
++ write_bl_len:4,
++ r2w_factor:3,
++ default_ecc:2,
++ wp_grp_enable:1,
++ wp_grp_size:5,
++ erase_grp_mult:5,
++ erase_grp_size:5,
++ c_size_mult:3,
++ vdd_w_curr_max:3,
++ vdd_w_curr_min:3,
++ vdd_r_curr_max:3,
++ vdd_r_curr_min:3,
++ c_size:12,
++ rsvd2:2,
++ dsr_imp:1,
++ read_blk_misalign:1,
++ write_blk_misalign:1,
++ read_bl_partial:1;
++
++ u16 read_bl_len:4,
++ ccc:12;
++ u8 tran_speed;
++ u8 nsac;
++ u8 taac;
++ u8 rsvd1:2,
++ spec_vers:4,
++ csd_structure:2;
++};
++
++struct _mmc_card_cid_rec { /* CID register contents */
++/* FIXME: BYTE_ORDER */
++ u8 mdt_year:4,
++ mdt_mon:4;
++ u32 psn;
++ u8 prv_minor:4,
++ prv_major:4;
++ u8 pnm[6];
++ u16 oid;
++ u8 mid;
++};
++
++/*
++ * Public card description
++ */
++struct _mmc_card_info_rec {
++ mmc_type_t type;
++ mmc_transfer_mode_t transfer_mode; /* current data transfer mode */
++ __u16 rca; /* card's RCA assigned during initialization */
++ struct _mmc_card_csd_rec csd;
++ struct _mmc_card_cid_rec cid;
++ __u32 tran_speed; /* kbits */
++ __u16 read_bl_len;
++ __u16 write_bl_len;
++ size_t capacity; /* card's capacity in bytes */
++};
++
++/*
++ * Micsellaneous defines
++ */
++#ifndef SEEK_SET
++#define SEEK_SET (0)
++#endif
++
++#ifndef SEEK_CUR
++#define SEEK_CUR (1)
++#endif
++
++#ifndef SEEK_END
++#define SEEK_END (2)
++#endif
++
++#ifndef TRUE
++#define TRUE (1)
++#endif
++
++#ifndef FALSE
++#define FALSE (0)
++#endif
++
++#endif /* __MMC_H__ */
+--- /dev/null
++++ linux-2.4.27/include/mmc/types.h
+@@ -0,0 +1,29 @@
++/*
++ * linux/include/linux/mmc/types.h
++ *
++ * Author: Vladimir Shebordaev
++ * Copyright: MontaVista Software Inc.
++ *
++ * $Id: types.h,v 0.2 2002/07/11 16:28:21 ted Exp ted $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef __MMC_TYPES_H__
++#define __MMC_TYPES_H__
++
++/* MMC card */
++typedef enum _mmc_type mmc_type_t;
++typedef enum _mmc_state mmc_state_t;
++typedef enum _mmc_transfer_mode mmc_transfer_mode_t;
++
++typedef struct _mmc_card_csd_rec mmc_card_csd_rec_t;
++typedef struct _mmc_card_cid_rec mmc_card_cid_rec_t;
++
++typedef struct _mmc_card_info_rec mmc_card_info_rec_t;
++typedef struct _mmc_card_info_rec *mmc_card_info_t;
++
++typedef enum _mmc_error mmc_error_t;
++
++#endif /* __MMC_TYPES_H__ */
+--- /dev/null
++++ linux-2.4.27/include/video/lcdctrl.h
+@@ -0,0 +1,61 @@
++/*
++ * lcdctrl.h
++ *
++ * Generic LCD control for brightness, contrast, etc.
++ * Device specific drivers implement a lcdctrl_device and
++ * provides access to it via lcdctrl_device_get_ops().
++ *
++ * Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * History:
++ * Mar 2002: Initial version [FB]
++ *
++ */
++#ifndef __LCD_CONTROL_H
++#define __LCD_CONTROL_H
++
++#define _LCDCTRL_IOCTL_ON 1
++#define _LCDCTRL_IOCTL_OFF 2
++#define _LCDCTRL_IOCTL_INTENSITY 3
++#define _LCDCTRL_IOCTL_BRIGHTNESS 4
++#define _LCDCTRL_IOCTL_CONTRAST 5
++#define _LCDCTRL_IOCTL_GET_BRIGHTNESS 6
++#define _LCDCTRL_IOCTL_GET_CONTRAST 7
++#define _LCDCTRL_IOCTL_GET_INTENSITY 8
++
++#define _LCD_CONTROL_NAME "lcdctrl"
++
++#define LCD_NO_SYNC 0
++#define LCD_SYNC_NEEDED 1
++
++int lcdctrl_enable( void);
++int lcdctrl_disable( void);
++
++/* intensity, contrast, and brightness take values
++ * between 0..100.
++ */
++int lcdctrl_set_intensity( int intensity);
++int lcdctrl_set_contrast( int contrast, int sync);
++int lcdctrl_set_brightness( int brightness);
++
++int lcdctrl_get_intensity( void);
++int lcdctrl_get_contrast( void);
++int lcdctrl_get_brightness( void);
++
++struct lcdctrl_device
++{
++ int (*init)( int*, int*, int*);
++ int (*enable)(void);
++ int (*disable)(void);
++ int (*set_intensity)( int i);
++ int (*set_brightness)( int b);
++ int (*set_contrast)( int c, int sync);
++};
++
++int lcdctrl_init( void);
++
++#endif
+--- linux-2.4.27/init/do_mounts.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/init/do_mounts.c
+@@ -394,6 +394,16 @@
+ }
+ #endif
+
++#ifdef CONFIG_ROOT_CRAMFS_LINEAR
++static int __init mount_linear_cramfs_root(void)
++{
++ void *data = root_mount_data;
++ if (sys_mount("/dev/root","/root","cramfs",root_mountflags,data) == 0)
++ return 1;
++ return 0;
++}
++#endif
++
+ static int __init create_dev(char *name, kdev_t dev, char *devfs_name)
+ {
+ void *handle;
+@@ -759,6 +769,16 @@
+
+ static void __init mount_root(void)
+ {
++#ifdef CONFIG_ROOT_CRAMFS_LINEAR
++ if (ROOT_DEV == MKDEV(0, 0)) {
++ if (mount_linear_cramfs_root()) {
++ sys_chdir("/root");
++ ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
++ printk("VFS: Mounted root (linear cramfs filesystem).\n");
++ return;
++ }
++ }
++#endif
+ #ifdef CONFIG_ROOT_NFS
+ if (MAJOR(ROOT_DEV) == NFS_MAJOR
+ && MINOR(ROOT_DEV) == NFS_MINOR) {
+--- linux-2.4.27/mm/memory.c~2.4.27-vrs1-pxa1
++++ linux-2.4.27/mm/memory.c
+@@ -1018,6 +1018,41 @@
+ return 1; /* Minor fault */
+
+ bad_wp_page:
++ if (pte_present(pte) && pte_read(pte)) {
++ /*
++ * Handle COW of XIP memory.
++ * Note that the source memory actually isn't a ram page so
++ * no struct page is associated to the source pte.
++ */
++ char *dst;
++ int ret;
++
++ spin_unlock(&mm->page_table_lock);
++ new_page = alloc_page(GFP_HIGHUSER);
++ if (!new_page)
++ return -1;
++
++ /* copy XIP data to memory */
++ dst = kmap_atomic(new_page, KM_USER0);
++ ret = copy_from_user(dst, (void*)address, PAGE_SIZE);
++ kunmap_atomic(dst, KM_USER0);
++
++ /* make sure pte didn't change while we dropped the lock */
++ spin_lock(&mm->page_table_lock);
++ if (!ret && pte_same(*page_table, pte)) {
++ ++mm->rss;
++ break_cow(vma, new_page, address, page_table);
++ lru_cache_add(new_page);
++ spin_unlock(&mm->page_table_lock);
++ return 1; /* Minor fault */
++ }
++
++ /* pte changed: back off */
++ spin_unlock(&mm->page_table_lock);
++ page_cache_release(new_page);
++ return ret ? -1 : 1;
++ }
++
+ spin_unlock(&mm->page_table_lock);
+ printk("do_wp_page: bogus page at address %08lx\n", address);
+ return -1;