* [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT
@ 2011-04-08 19:33 Jan Kobler
2011-04-08 19:33 ` [mpc5125-twr 2/2] Linux kernel for mpc5125-twr Jan Kobler
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Jan Kobler @ 2011-04-08 19:33 UTC (permalink / raw)
To: openembedded-devel
Freescale Development Kit TWR-MPC5125-KIT
Vendor page: http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=TWR-MPC5125-KIT
The name mpc5125-twr is used by Freescale in the Linux kernel for this board.
Signed-off-by: Jan Kobler <eng1@koblersystems.de>
---
MAINTAINERS | 2 +-
conf/distro/include/sane-feed.inc | 1 +
conf/machine/mpc5125-twr.conf | 27 +++++++++++++++++++++++++++
contrib/angstrom/sort.sh | 2 +-
recipes/linux/linux_2.6.29.bb | 9 +++++++++
5 files changed, 39 insertions(+), 2 deletions(-)
create mode 100644 conf/machine/mpc5125-twr.conf
diff --git a/MAINTAINERS b/MAINTAINERS
index 45e92d1..c0962cc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -141,7 +141,7 @@ Recipes: net-snmp, ebtables, ethtool, arpwatch, lib*-perl
Person: Jan Kobler
Mail: eng1@koblersystems.de
Interests: embedded systems, powerpc, arm
-Machines: pcm043
+Machines: mpc5125-twr, pcm043
Person: Jan Luebbe
Mail: jluebbe@lasnet.de
diff --git a/conf/distro/include/sane-feed.inc b/conf/distro/include/sane-feed.inc
index 70fc7a9..821f5bf 100644
--- a/conf/distro/include/sane-feed.inc
+++ b/conf/distro/include/sane-feed.inc
@@ -156,6 +156,7 @@ FEED_ARCH_storcenter = "ppc603e"
FEED_ARCH_turbostation = "ppc603e"
FEED_ARCH_mpc8313e-rdb = "ppce300c3"
FEED_ARCH_mpc8323e-rdb = "ppce300c2"
+FEED_ARCH_mpc5125-twr = "ppce300c3"
# strongarm machines, no EABI
diff --git a/conf/machine/mpc5125-twr.conf b/conf/machine/mpc5125-twr.conf
new file mode 100644
index 0000000..71432cd
--- /dev/null
+++ b/conf/machine/mpc5125-twr.conf
@@ -0,0 +1,27 @@
+#@TYPE: Machine
+#@Name: Freescale MPC5125-TWR
+#@DESCRIPTION: Machine configuration for Freescale MPC5125-TWR
+
+# Vendor page: http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=TWR-MPC5125-KIT
+
+TARGET_ARCH = "powerpc"
+PACKAGE_EXTRA_ARCHS = "ppc"
+MACHINE_FEATURES = "kernel26 usbhost ext2"
+
+PREFERRED_PROVIDER_virtual/kernel = "linux"
+PREFERRED_VERSION_linux = "2.6.29"
+PREFERRED_VERSION_linux-libc-headers = "2.6.29"
+
+# used by sysvinit_2
+SERIAL_CONSOLE = "115200 ttyPSC0"
+
+IMAGE_FSTYPES += "tar.gz"
+
+KERNEL_IMAGETYPE = "uImage"
+UBOOT_ENTRYPOINT = "0x0"
+KERNEL_DEVICETREE_mpc5125-twr = "arch/${ARCH}/boot/dts/mpc5125-twr.dts"
+
+# used by opie-collections.inc
+ROOT_FLASH_SIZE = "32"
+
+require conf/machine/include/tune-ppce300c3.inc
diff --git a/contrib/angstrom/sort.sh b/contrib/angstrom/sort.sh
index ca13ce2..3a0db52 100755
--- a/contrib/angstrom/sort.sh
+++ b/contrib/angstrom/sort.sh
@@ -112,7 +112,7 @@ case "$arch" in
"ppce300c2")
machines="mpc8323e-rdb" ;;
"ppce300c3")
- machines="boc01 mpc8313e-rdb mpc8315e-rdb" ;;
+ machines="boc01 mpc5125-twr mpc8313e-rdb mpc8315e-rdb" ;;
"ppce500")
machines="tqm8540" ;;
"ppce500v2")
diff --git a/recipes/linux/linux_2.6.29.bb b/recipes/linux/linux_2.6.29.bb
index 2b80884..5d4809b 100644
--- a/recipes/linux/linux_2.6.29.bb
+++ b/recipes/linux/linux_2.6.29.bb
@@ -22,6 +22,12 @@ SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-2.6.29.tar.bz2;name=k
${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/patch-${PV}.6.bz2;apply=yes;name=stablepatch \
file://defconfig"
+# mpc5125-twr uses linux-2.6.29.1
+SRC_URI_mpc5125-twr = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-2.6.29.tar.bz2;name=kernel \
+ ${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/patch-${PV}.1.bz2;apply=yes;name=stablepatch1 \
+ file://defconfig \
+ file://mpc5125-twr.patch"
+
SRC_URI_append_boc01 = "\
file://boc01.dts \
file://boc01.dts.v1 \
@@ -91,3 +97,6 @@ SRC_URI[kernel.md5sum] = "64921b5ff5cdadbccfcd3820f03be7d8"
SRC_URI[kernel.sha256sum] = "58a5ea16d499fe06f90fcbf1d687d1235d2cb9bc28bf979867bd3faadf38fc3f"
SRC_URI[stablepatch.md5sum] = "0317760b52c9ac7a11de997da19a366e"
SRC_URI[stablepatch.sha256sum] = "0294d475cbbc6cf43db25e64b92616309086cad6be4ee463f7f4b1d16d285c27"
+# linux patch-2.6.29.1
+SRC_URI[stablepatch1.md5sum] = "87c6fbf4096b644d66d4da8bb00641a5"
+SRC_URI[stablepatch1.sha256sum] = "0c44a41816082602f9d2bd45524d85f6e5fa8e4a6a9a15861048ca2aaf068d8f"
--
1.7.3.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [mpc5125-twr 2/2] Linux kernel for mpc5125-twr
2011-04-08 19:33 [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT Jan Kobler
@ 2011-04-08 19:33 ` Jan Kobler
2011-04-08 19:43 ` [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT Tom Rini
2011-04-08 20:15 ` mpc5125-twr: Tutorial Jan Kobler
2 siblings, 0 replies; 8+ messages in thread
From: Jan Kobler @ 2011-04-08 19:33 UTC (permalink / raw)
To: openembedded-devel
Freescale is shipping a Linux kernel 2.6.29-v2010041601 for the TWR-MPC5125-KIT in
http://www.freescale.com/files/soft_dev_tools/software/board_support_packages/TWRMPC5125LinuxBSP.rar
The patch mpc5125-twr.patch has been created by comparing
the Freescale Linux kernel with Linux kernel version 2.6.29.1
The defconfig file is the file linux-2.6.29-v2010041601/arch/powerpc/configs/mpc5125_twr_defconfig.
Signed-off-by: Jan Kobler <eng1@koblersystems.de>
---
recipes/linux/linux-2.6.29/mpc5125-twr/defconfig | 2274 +
.../linux-2.6.29/mpc5125-twr/mpc5125-twr.patch |48475 ++++++++++++++++++++
2 files changed, 50749 insertions(+), 0 deletions(-)
create mode 100644 recipes/linux/linux-2.6.29/mpc5125-twr/defconfig
create mode 100644 recipes/linux/linux-2.6.29/mpc5125-twr/mpc5125-twr.patch
diff --git a/recipes/linux/linux-2.6.29/mpc5125-twr/defconfig b/recipes/linux/linux-2.6.29/mpc5125-twr/defconfig
new file mode 100644
index 0000000..9601c6a
--- /dev/null
+++ b/recipes/linux/linux-2.6.29/mpc5125-twr/defconfig
@@ -0,0 +1,2274 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29.1
+# Thu Mar 18 13:38:38 2010
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+# CONFIG_ALTIVEC is not set
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+# CONFIG_SMP is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_AUDIT_TREE=y
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+# CONFIG_USER_SCHED is not set
+CONFIG_CGROUP_SCHED=y
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_NS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_RESOURCE_COUNTERS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+CONFIG_RELAY=y
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_PCSPKR_PLATFORM=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+CONFIG_MARKERS=y
+CONFIG_OPROFILE=m
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_BLK_DEV_BSG=y
+CONFIG_BLK_DEV_INTEGRITY=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_FREEZER=y
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+CONFIG_CLASSIC32=y
+CONFIG_PPC_CHRP=y
+CONFIG_PPC_MPC512x=y
+CONFIG_PPC_MPC5125=y
+# CONFIG_PPC_MPC5121 is not set
+# CONFIG_MPC5121_ADS is not set
+CONFIG_PPC_MERGE=y
+CONFIG_MPC5125_TWR=y
+# CONFIG_MPC5121_GENERIC is not set
+# CONFIG_MPC5121_ADS_HIB is not set
+CONFIG_MPC5121_PM_TEST=y
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_EMBEDDED6xx is not set
+CONFIG_PPC_NATIVE=y
+# CONFIG_UDBG_RTAS_CONSOLE is not set
+CONFIG_IPIC=y
+CONFIG_MPIC=y
+# CONFIG_MPIC_WEIRD is not set
+CONFIG_PPC_I8259=y
+CONFIG_PPC_RTAS=y
+# CONFIG_RTAS_ERROR_LOGGING is not set
+# CONFIG_RTAS_PROC is not set
+# CONFIG_MMIO_NVRAM is not set
+CONFIG_PPC_MPC106=y
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_TAU is not set
+# CONFIG_QUICC_ENGINE is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_SCHED_HRTICK=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_BINFMT_ELF=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_PPC_NEED_DMA_SYNC_OPS=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_MIGRATION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_UNEVICTABLE_LRU is not set
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_EXTRA_TARGETS=""
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_HIBERNATION is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_ISA is not set
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+CONFIG_ADVANCED_OPTIONS=y
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_AXEMBX_RESERVE_BOOL=y
+CONFIG_AXEMBX_RESERVE_START=0x00400000
+CONFIG_AXE_RESERVE_SIZE=0x00100000
+CONFIG_MBX_RESERVE_SIZE=0x0
+# CONFIG_PAGE_OFFSET_BOOL is not set
+CONFIG_PAGE_OFFSET=0xc0000000
+# CONFIG_KERNEL_START_BOOL is not set
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+# CONFIG_TASK_SIZE_BOOL is not set
+CONFIG_TASK_SIZE=0xc0000000
+# CONFIG_CONSISTENT_START_BOOL is not set
+CONFIG_CONSISTENT_START=0xff100000
+# CONFIG_CONSISTENT_SIZE_BOOL is not set
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_IPCOMP=m
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+# CONFIG_DEFAULT_BIC is not set
+CONFIG_DEFAULT_CUBIC=y
+# CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_VEGAS is not set
+# CONFIG_DEFAULT_WESTWOOD is not set
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CT_ACCT=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=m
+CONFIG_NF_CT_PROTO_GRE=m
+CONFIG_NF_CT_PROTO_SCTP=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NETFILTER_TPROXY=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+# CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT is not set
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_IPV6 is not set
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_AH_ESP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_NF_NAT_SNMP_BASIC=m
+CONFIG_NF_NAT_PROTO_DCCP=m
+CONFIG_NF_NAT_PROTO_GRE=m
+CONFIG_NF_NAT_PROTO_UDPLITE=m
+CONFIG_NF_NAT_PROTO_SCTP=m
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+CONFIG_NF_NAT_AMANDA=m
+CONFIG_NF_NAT_PPTP=m
+CONFIG_NF_NAT_H323=m
+CONFIG_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# DECnet: Netfilter Configuration
+#
+CONFIG_DECNET_NF_GRABULATOR=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+CONFIG_IP_DCCP_CCID3=y
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_CCID3_RTO=100
+CONFIG_IP_DCCP_TFRC_LIB=y
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_TIPC_ZONES=3
+CONFIG_TIPC_CLUSTERS=1
+CONFIG_TIPC_NODES=255
+CONFIG_TIPC_SLAVE_NODES=0
+CONFIG_TIPC_PORTS=8191
+CONFIG_TIPC_LOG=0
+# CONFIG_TIPC_DEBUG is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_BRIDGE=m
+# CONFIG_NET_DSA is not set
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_DECNET=m
+CONFIG_DECNET_ROUTER=y
+CONFIG_LLC=m
+CONFIG_LLC2=m
+CONFIG_IPX=m
+CONFIG_IPX_INTERN=y
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_X25=m
+CONFIG_LAPB=m
+CONFIG_ECONET=m
+CONFIG_ECONET_AUNUDP=y
+CONFIG_ECONET_NATIVE=y
+CONFIG_WAN_ROUTER=m
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_SCH_FIFO=y
+CONFIG_DCB=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=y
+CONFIG_CAN_RAW=y
+# CONFIG_CAN_BCM is not set
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_VCAN=y
+# CONFIG_CAN_DEBUG_DEVICES is not set
+CONFIG_CAN_MSCAN=y
+CONFIG_CAN_MPC52XX=y
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+CONFIG_FIB_RULES=y
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+CONFIG_RFKILL=m
+CONFIG_RFKILL_INPUT=m
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=m
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS 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 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_MPC5125_NFC=y
+CONFIG_MTD_NAND_FSL=y
+CONFIG_MTD_NAND_MPC5125_HARDWARE_ECC_CORRECTION=y
+# CONFIG_NFC_DMA_ENABLE is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=m
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_FD=m
+CONFIG_BLK_CPQ_DA=m
+CONFIG_BLK_CPQ_CISS_DA=m
+CONFIG_CISS_SCSI_TAPE=y
+CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_UMEM=m
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_UB=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_BLK_DEV_RAM_SIZE=32768
+# CONFIG_BLK_DEV_XIP is not set
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_ATA_OVER_ETH=m
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_TIFM_CORE=m
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+CONFIG_SCSI_TGT=m
+CONFIG_SCSI_NETLINK=y
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+# CONFIG_SCSI_FC_TGT_ATTRS is not set
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+CONFIG_SCSI_SAS_LIBSAS=m
+# CONFIG_SCSI_SAS_HOST_SMP is not set
+# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set
+CONFIG_SCSI_SRP_ATTRS=m
+# CONFIG_SCSI_SRP_TGT_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+CONFIG_ISCSI_TCP=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+CONFIG_AIC79XX_DEBUG_ENABLE=y
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC94XX=m
+# CONFIG_AIC94XX_DEBUG is not set
+CONFIG_SCSI_DPT_I2O=m
+CONFIG_SCSI_ADVANSYS=m
+CONFIG_SCSI_ARCMSR=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=m
+CONFIG_MEGARAID_MAILBOX=m
+# CONFIG_MEGARAID_LEGACY is not set
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_SCSI_BUSLOGIC=m
+CONFIG_LIBFC=m
+CONFIG_FCOE=m
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_EATA=m
+# CONFIG_SCSI_EATA_TAGGED_QUEUE is not set
+# CONFIG_SCSI_EATA_LINKED_COMMANDS is not set
+CONFIG_SCSI_EATA_MAX_TAGS=16
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+CONFIG_SCSI_IPS=m
+# CONFIG_SCSI_INITIO is not set
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_MVSAS=m
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+CONFIG_SCSI_SYM53C8XX_MMIO=y
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_SCSI_LPFC=m
+# CONFIG_SCSI_LPFC_DEBUG_FS is not set
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_DC390T=m
+CONFIG_SCSI_NSP32=m
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_SCSI_SRP=m
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+CONFIG_FIREWIRE=m
+CONFIG_FIREWIRE_OHCI=m
+CONFIG_FIREWIRE_OHCI_DEBUG=y
+CONFIG_FIREWIRE_SBP2=m
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+CONFIG_IFB=m
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_MACVLAN=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_ARCNET=m
+CONFIG_ARCNET_1201=m
+CONFIG_ARCNET_1051=m
+CONFIG_ARCNET_RAW=m
+CONFIG_ARCNET_CAP=m
+# CONFIG_ARCNET_COM90xx is not set
+CONFIG_ARCNET_COM90xxIO=m
+# CONFIG_ARCNET_RIM_I is not set
+CONFIG_ARCNET_COM20020=m
+CONFIG_ARCNET_COM20020_PCI=m
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_ATL2 is not set
+CONFIG_FS_ENET=y
+CONFIG_FS_ENET_MPC5121_FEC=y
+# CONFIG_FS_ENET_MPC5125_FEC2 is not set
+CONFIG_FS_ENET_HAS_FEC=y
+CONFIG_FS_ENET_MDIO_FEC=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_MLX4_CORE=m
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_CDC_SUBSET=m
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_ARMLINUX is not set
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_HSO=m
+# CONFIG_WAN is not set
+# CONFIG_ATM_DRIVERS is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+CONFIG_SLIP=m
+# CONFIG_SLIP_COMPRESSED is not set
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_NET_FC is not set
+CONFIG_NETCONSOLE=m
+# CONFIG_NETCONSOLE_DYNAMIC is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_FF_MEMLESS=y
+CONFIG_INPUT_POLLDEV=m
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_I8042=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_RAW=m
+# CONFIG_SERIO_XILINX_XPS_PS2 is not set
+CONFIG_GAMEPORT=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_FM801=m
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_NOZOMI=m
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_MPC52xx=y
+CONFIG_SERIAL_MPC52xx_CONSOLE=y
+CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200
+CONFIG_SERIAL_JSM=m
+CONFIG_UNIX98_PTYS=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_BRIQ_PANEL is not set
+# CONFIG_HVC_RTAS is not set
+# CONFIG_HVC_UDBG is not set
+CONFIG_IPMI_HANDLER=m
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+CONFIG_IPMI_WATCHDOG=m
+CONFIG_IPMI_POWEROFF=m
+CONFIG_HW_RANDOM=m
+CONFIG_NVRAM=y
+# CONFIG_R3964 is not set
+CONFIG_APPLICOM=m
+# CONFIG_RAW_DRIVER is not set
+CONFIG_TCG_TPM=m
+CONFIG_TCG_NSC=m
+CONFIG_TCG_ATMEL=m
+CONFIG_DEVPORT=y
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCA=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+CONFIG_I2C_ISCH=m
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+
+#
+# Mac SMBus host controller drivers
+#
+CONFIG_I2C_HYDRA=m
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_MPC=m
+CONFIG_I2C_OCORES=m
+CONFIG_I2C_SIMTEC=m
+
+#
+# External I2C/SMBus adapter drivers
+#
+CONFIG_I2C_PARPORT_LIGHT=m
+CONFIG_I2C_TAOS_EVM=m
+CONFIG_I2C_TINY_USB=m
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+CONFIG_I2C_VOODOO3=m
+
+#
+# Other I2C/SMBus bus drivers
+#
+CONFIG_I2C_PCA_PLATFORM=m
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_DS1682=m
+CONFIG_SENSORS_PCF8574=m
+CONFIG_PCF8575=m
+CONFIG_SENSORS_PCA9539=m
+CONFIG_SENSORS_PCF8591=m
+CONFIG_SENSORS_MAX6875=m
+CONFIG_SENSORS_TSL2550=m
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+CONFIG_POWER_SUPPLY_DEBUG=y
+# CONFIG_PDA_POWER is not set
+# CONFIG_WM8350_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_CHARGER_PCF50633 is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=m
+CONFIG_SSB_SPROM=y
+CONFIG_SSB_PCIHOST_POSSIBLE=y
+CONFIG_SSB_PCIHOST=y
+# CONFIG_SSB_B43_PCI_BRIDGE is not set
+# CONFIG_SSB_DEBUG is not set
+CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
+CONFIG_SSB_DRIVER_PCICORE=y
+
+#
+# Multifunction device drivers
+#
+CONFIG_MFD_CORE=m
+CONFIG_MFD_SM501=m
+CONFIG_HTC_PASIC3=m
+# CONFIG_MFD_TMIO is not set
+CONFIG_MFD_WM8400=m
+CONFIG_MFD_WM8350=m
+CONFIG_MFD_WM8350_I2C=m
+CONFIG_MFD_PCF50633=m
+CONFIG_PCF50633_ADC=m
+CONFIG_PCF50633_GPIO=m
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_V4L2_COMMON=m
+# CONFIG_VIDEO_ALLOW_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+CONFIG_DVB_CORE=m
+CONFIG_VIDEO_MEDIA=m
+
+#
+# Multimedia drivers
+#
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=m
+# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_VIDEO_V4L2=m
+# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_DVB_DYNAMIC_MINORS is not set
+# CONFIG_DVB_CAPTURE_DRIVERS is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+CONFIG_AGP=m
+CONFIG_DRM=m
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_MGA=m
+# CONFIG_DRM_SIS is not set
+CONFIG_DRM_VIA=m
+CONFIG_DRM_SAVAGE=m
+CONFIG_VGASTATE=m
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=m
+CONFIG_FB_SYS_COPYAREA=m
+CONFIG_FB_SYS_IMAGEBLIT=m
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=m
+CONFIG_FB_DEFERRED_IO=y
+CONFIG_FB_SVGALIB=m
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_CIRRUS=m
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_OF is not set
+# CONFIG_FB_CT65550 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_UVESA is not set
+CONFIG_FB_S1D13XXX=m
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+CONFIG_FB_S3=m
+CONFIG_FB_SAVAGE=m
+# CONFIG_FB_SAVAGE_I2C is not set
+# CONFIG_FB_SAVAGE_ACCEL is not set
+# CONFIG_FB_SIS is not set
+CONFIG_FB_VIA=m
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+CONFIG_FB_VT8623=m
+CONFIG_FB_TRIDENT=m
+# CONFIG_FB_TRIDENT_ACCEL is not set
+CONFIG_FB_ARK=m
+CONFIG_FB_PM3=m
+# CONFIG_FB_CARMINE is not set
+CONFIG_FB_FSL_DIU=y
+CONFIG_FSL_DIU_FLIP_ON_VSYNC=y
+# CONFIG_FB_TMIO is not set
+CONFIG_FB_SM501=m
+CONFIG_FB_IBM_GXT4500=m
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_METRONOME=m
+CONFIG_FB_MB862XX=m
+# CONFIG_FB_MB862XX_PCI_GDC is not set
+# CONFIG_FB_MB862XX_LIME is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=m
+
+#
+# Display hardware drivers
+#
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_SEQUENCER=y
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+CONFIG_SND_DEBUG_VERBOSE=y
+CONFIG_SND_PCM_XRUN_DEBUG=y
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
+# CONFIG_SND_PCI is not set
+# CONFIG_SND_PPC is not set
+# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
+
+#
+# ALSA SoC audio for Freescale SOCs
+#
+CONFIG_SND_SOC_MPC5121=y
+CONFIG_SND_SOC_MPC5121_ADS=y
+# CONFIG_SND_SOC_MPC5121_I2S is not set
+CONFIG_SND_SOC_I2C_AND_SPI=m
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_AC97_CODEC=y
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+CONFIG_HIDRAW=y
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_LOGITECH=y
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_GREENASIA_FF=m
+CONFIG_HID_TOPSEED=y
+CONFIG_THRUSTMASTER_FF=m
+CONFIG_ZEROPLUS_FF=m
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_MON is not set
+CONFIG_USB_WUSB=m
+CONFIG_USB_WUSB_CBAF=m
+# CONFIG_USB_WUSB_CBAF_DEBUG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_EHCI_BIG_ENDIAN_DESC=y
+CONFIG_USB_EHCI_FSL=y
+CONFIG_USB_EHCI_HCD_PPC_OF=y
+# CONFIG_USB_OXU210HP_HCD is not set
+CONFIG_USB_ISP116X_HCD=m
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_HCD_SSB is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_U132_HCD=m
+CONFIG_USB_SL811_HCD=m
+CONFIG_USB_R8A66597_HCD=m
+CONFIG_USB_WHCI_HCD=m
+CONFIG_USB_HWA_HCD=m
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_WDM=m
+CONFIG_USB_TMC=m
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+#
+
+#
+# see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# 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_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# USB Imaging devices
+#
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+# CONFIG_USB_SERIAL_CP2101 is not set
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_FUNSOFT=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+# CONFIG_USB_SERIAL_KEYSPAN_MPR 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_USA19QW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_MOTOROLA=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_SIEMENS_MPI=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+# CONFIG_USB_SERIAL_TI is not set
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_DEBUG=m
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_ADUTUX=m
+CONFIG_USB_SEVSEG=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_BERRY_CHARGE=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+# CONFIG_USB_PHIDGET is not set
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+CONFIG_USB_APPLEDISPLAY=m
+# CONFIG_USB_SISUSBVGA is not set
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+CONFIG_USB_IOWARRIOR=m
+CONFIG_USB_TEST=m
+CONFIG_USB_ISIGHTFW=m
+CONFIG_USB_VST=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_UWB=m
+CONFIG_UWB_HWA=m
+CONFIG_UWB_WHCI=m
+CONFIG_UWB_WLP=m
+CONFIG_UWB_I1480U=m
+CONFIG_UWB_I1480U_WLP=m
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_SDIO_UART=m
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=m
+CONFIG_MMC_SDHCI_PCI=m
+CONFIG_MMC_RICOH_MMC=m
+CONFIG_MMC_MPC5121=y
+# CONFIG_MMC_MPC5121_USE_DMA is not set
+# CONFIG_MMC_MPC5121_USE_CARD_INSERTION_INT is not set
+CONFIG_MMC_WBSD=m
+CONFIG_MMC_TIFM_SD=m
+CONFIG_MEMSTICK=m
+# CONFIG_MEMSTICK_DEBUG is not set
+
+#
+# MemoryStick drivers
+#
+# CONFIG_MEMSTICK_UNSAFE_RESUME is not set
+CONFIG_MSPRO_BLOCK=m
+
+#
+# MemoryStick Host Controller Drivers
+#
+CONFIG_MEMSTICK_TIFM_MS=m
+CONFIG_MEMSTICK_JMICRON_38X=m
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_USER_MAD=m
+CONFIG_INFINIBAND_USER_ACCESS=m
+CONFIG_INFINIBAND_USER_MEM=y
+CONFIG_INFINIBAND_ADDR_TRANS=y
+CONFIG_INFINIBAND_MTHCA=m
+CONFIG_INFINIBAND_MTHCA_DEBUG=y
+CONFIG_INFINIBAND_AMSO1100=m
+# CONFIG_INFINIBAND_AMSO1100_DEBUG is not set
+CONFIG_MLX4_INFINIBAND=m
+CONFIG_INFINIBAND_NES=m
+# CONFIG_INFINIBAND_NES_DEBUG is not set
+CONFIG_INFINIBAND_IPOIB=m
+# CONFIG_INFINIBAND_IPOIB_CM is not set
+CONFIG_INFINIBAND_IPOIB_DEBUG=y
+# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set
+CONFIG_INFINIBAND_SRP=m
+CONFIG_INFINIBAND_ISER=m
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS2068A is not set
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_WM8350 is not set
+# CONFIG_RTC_DRV_PCF50633 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PPC is not set
+CONFIG_RTC_DRV_MPC5121=y
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+CONFIG_FSL_DMA=y
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_NET_DMA is not set
+# CONFIG_DMATEST is not set
+CONFIG_UIO=m
+CONFIG_UIO_CIF=m
+CONFIG_UIO_PDRV=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_UIO_SMX=m
+CONFIG_UIO_SERCOS3=m
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4DEV_COMPAT=y
+CONFIG_EXT4_FS_XATTR=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_GENERIC_ACL=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=y
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_SUNRPC_XPRT_RDMA=m
+CONFIG_SUNRPC_REGISTER_V4=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+CONFIG_AMIGA_PARTITION=y
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_KARMA_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8895-i"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+CONFIG_CRC7=m
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_STACKTRACE=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+
+#
+# Tracers
+#
+# CONFIG_FIREWIRE_OHCI_REMOTE_DMA is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_IRQSTACKS is not set
+# CONFIG_VIRQ_DEBUG is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+CONFIG_SECURITYFS=y
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_FIPS=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+CONFIG_CRYPTO_XCBC=m
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SALSA20=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_LZO=m
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_HW is not set
+CONFIG_PPC_CLOCK=y
+CONFIG_PPC_LIB_RHEAP=y
+# CONFIG_VIRTUALIZATION is not set
diff --git a/recipes/linux/linux-2.6.29/mpc5125-twr/mpc5125-twr.patch b/recipes/linux/linux-2.6.29/mpc5125-twr/mpc5125-twr.patch
new file mode 100644
index 0000000..f68f98d
--- /dev/null
+++ b/recipes/linux/linux-2.6.29/mpc5125-twr/mpc5125-twr.patch
@@ -0,0 +1,48475 @@
+diff -Naur linux-2.6.29/arch/powerpc/boot/dts/mpc5125-twr.dts linux-2.6.29-v2010041601/arch/powerpc/boot/dts/mpc5125-twr.dts
+--- linux-2.6.29/arch/powerpc/boot/dts/mpc5125-twr.dts 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/boot/dts/mpc5125-twr.dts 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,426 @@
++/*
++ * STx/Freescale ADS5125 MPC5125 silicon
++ *
++ * Copyright (C) 2009 Freescale Semiconductor Inc. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++/dts-v1/;
++
++/ {
++ model = "mpc5125ads";
++ compatible = "fsl,mpc5125ads";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ PowerPC,5125@0 {
++ device_type = "cpu";
++ reg = <0>;
++ d-cache-line-size = <0x20>; // 32 bytes
++ i-cache-line-size = <0x20>; // 32 bytes
++ d-cache-size = <0x8000>; // L1, 32K
++ i-cache-size = <0x8000>; // L1, 32K
++ timebase-frequency = <49500000>;// 49.5 MHz (csb/4)
++ bus-frequency = <198000000>; // 198 MHz csb bus
++ clock-frequency = <396000000>; // 396 MHz ppc core
++ };
++ };
++
++ memory {
++ device_type = "memory";
++ reg = <0x00000000 0x10000000>; // 256MB at 0
++ };
++
++ sram@30000000 {
++ compatible = "fsl,mpc5121-sram";
++ reg = <0x30000000 0x08000>; // 32K at 0x30000000
++ };
++
++ nfc@40000000 {
++ compatible = "fsl,mpc5125-nfc";
++ reg = <0x40000000 0x100000>; // 1M at 0x40000000
++ interrupts = <6 0x8>;
++ interrupt-parent = < &ipic >;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ bank-width = <1>;
++ write-size = <4096>;
++ spare-size = <218>;
++ chips = <1>;
++ nand-loader@0 {
++ label = "loader";
++ reg = <0x000000000 0x00100000>;
++ };
++ nand-uboot@100000 {
++ label = "uboot";
++ reg = <0x00100000 0x00100000>;
++ };
++ nand-envirement@200000 {
++ label = "envirment";
++ reg = <0x00200000 0x00100000>;
++ read-only;
++ };
++ nand-kernel@300000 {
++ label = "kernel";
++ reg = <0x00300000 0x00800000>;
++ };
++ devicetree@b00000 {
++ label = "device-tree";
++ reg = <0x00b00000 0x00100000>;
++ };
++ rootfs@c00000 {
++ label = "rootfs";
++ reg = <0x00c00000 0x800000>;
++ };
++ filesystem@1400000 {
++ label = "filesystem";
++ reg = <0x01400000 0x7ec00000>;
++ };
++ mqx@80000000 {
++ label = "mqx";
++ reg = <0x80000000 0x06400000>;
++ };
++ data@86400000 {
++ label = "data";
++ reg = <0x86400000 0x79C00000>;
++ };
++
++ };
++
++/*
++ localbus@80000020 {
++ compatible = "fsl,mpc5121ads-localbus";
++ #address-cells = <2>;
++ #size-cells = <1>;
++ reg = <0x80000020 0x40>;
++
++ ranges = <0x0 0x0 0xfe000000 0x02000000
++ 0x2 0x0 0x82000000 0x00008000>;
++
++ flash@0,0 {
++ compatible = "cfi-flash";
++ reg = <0 0x0 0x2000000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ bank-width = <2>;
++ device-width = <2>;
++ protected@0 {
++ label = "protected";
++ reg = <0x00000000 0x00040000>; // first sector is protected
++ read-only;
++ };
++ filesystem@40000 {
++ label = "filesystem";
++ reg = <0x00040000 0x01a80000>; // 26.25M for filesystem
++ };
++ kernel@1c40000 {
++ label = "kernel";
++ reg = <0x01ac0000 0x00400000>; // 4M for kernel
++ };
++ device-tree@1ec0000 {
++ label = "device-tree";
++ reg = <0x01ec0000 0x00040000>; // one sector for device tree
++ };
++ u-boot@1f00000 {
++ label = "u-boot";
++ reg = <0x01f00000 0x00100000>; // 1M for u-boot
++ read-only;
++ };
++ };
++ };
++*/
++ soc@80000000 {
++ compatible = "fsl,mpc5121-immr";
++ device_type = "soc";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ #interrupt-cells = <2>;
++ ranges = <0x0 0x80000000 0x400000>;
++ reg = <0x80000000 0x400000>;
++ bus-frequency = <66000000>; // 66 MHz ips bus
++
++
++ // IPIC
++ // interrupts cell = <intr #, sense>
++ // sense values match linux IORESOURCE_IRQ_* defines:
++ // sense == 8: Level, low assertion
++ // sense == 2: Edge, high-to-low change
++ //
++ ipic: interrupt-controller@c00 {
++ compatible = "fsl,mpc5121-ipic", "fsl,ipic";
++ interrupt-controller;
++ #address-cells = <0>;
++ #interrupt-cells = <2>;
++ reg = <0xc00 0x100>;
++ };
++
++ rtc@a00 { // Real time clock
++ compatible = "fsl,mpc5121-rtc";
++ reg = <0xa00 0x100>;
++ interrupts = <79 0x8 80 0x8>;
++ interrupt-parent = < &ipic >;
++ };
++
++ reset@e00 { // Reset module
++ compatible = "fsl,mpc5121-reset";
++ reg = <0xe00 0x100>;
++ };
++
++ clock@f00 { // Clock control
++ compatible = "fsl,mpc5121rev2-clock", "fsl,mpc5121-clock";
++ reg = <0xf00 0x100>;
++ };
++
++ pmc@1000{ //Power Management Controller
++ compatible = "fsl,mpc5121-pmc";
++ reg = <0x1000 0x100>;
++ interrupts = <83 0x2>;
++ interrupt-parent = < &ipic >;
++ };
++
++ gpio@1100 {
++ compatible = "fsl,mpc5125-gpio";
++ cell-index = <0>;
++ reg = <0x1100 0x080>;
++ interrupts = <78 0x8>;
++ interrupt-parent = < &ipic >;
++ };
++
++ gpio@1180 {
++ compatible = "fsl,mpc5125-gpio1";
++ cell-index = <1>;
++ reg = <0x1180 0x080>;
++ interrupts = <78 0x8>;
++ interrupt-parent = < &ipic >;
++ };
++
++ mscan@1300 {
++ compatible = "fsl,mpc5121rev2-mscan";
++ cell-index = <0>;
++ interrupts = <12 0x8>;
++ interrupt-parent = < &ipic >;
++ reg = <0x1300 0x80>;
++ };
++
++ mscan@1380 {
++ compatible = "fsl,mpc5121rev2-mscan";
++ cell-index = <1>;
++ interrupts = <13 0x8>;
++ interrupt-parent = < &ipic >;
++ reg = <0x1380 0x80>;
++ };
++
++ sdhc@1500 {
++ compatible = "fsl,mpc5125-sdhc";
++ interrupts = <8 0x8>;
++ interrupt-parent = < &ipic >;
++ reg = <0x1500 0x100>;
++ };
++
++ i2c@1700 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "fsl-i2c";
++ cell-index = <0>;
++ reg = <0x1700 0x20>;
++ interrupts = <0x9 0x8>;
++ interrupt-parent = < &ipic >;
++ fsl5200-clocking;
++ };
++
++ i2c@1720 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "fsl-i2c";
++ cell-index = <1>;
++ reg = <0x1720 0x20>;
++ interrupts = <0xa 0x8>;
++ interrupt-parent = < &ipic >;
++ fsl5200-clocking;
++ };
++
++ i2c@1740 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "fsl-i2c";
++ cell-index = <2>;
++ reg = <0x1740 0x20>;
++ interrupts = <0xb 0x8>;
++ interrupt-parent = < &ipic >;
++ fsl5200-clocking;
++ };
++
++ i2ccontrol@1760 {
++ compatible = "fsl,mpc5121-i2c-ctrl";
++ reg = <0x1760 0x8>;
++ };
++
++ diu@2100 {
++ device_type = "display";
++ compatible = "fsl-diu";
++ reg = <0x2100 0x100>;
++ interrupts = <64 0x8>;
++ interrupt-parent = < &ipic >;
++ };
++
++ // MPC5125e has two more CAN ports
++ // but they are not used on ADS5125
++ //mscan@2300 {
++ // compatible = "fsl,mpc5121rev2-mscan";
++ // cell-index = <2>;
++ // interrupts = <90 0x8>;
++ // interrupt-parent = < &ipic >;
++ // reg = <0x2300 0x80>;
++ //};
++
++ //mscan@2380 {
++ // compatible = "fsl,mpc5121rev2-mscan";
++ // cell-index = <3>;
++ // interrupts = <91 0x8>;
++ // interrupt-parent = < &ipic >;
++ // reg = <0x2380 0x80>;
++ //};
++
++ mdio@2800 {
++ device_type = "mdio";
++ compatible = "fsl,mpc5121-fec-mdio";
++ reg = <0x2800 0x800>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ phy0: ethernet-phy@0 {
++ reg = <1>;
++ device_type = "ethernet-phy";
++ };
++ };
++
++ ethernet@2800 {
++ device_type = "network";
++ compatible = "fsl,mpc5121-fec";
++ reg = <0x2800 0x800>;
++ local-mac-address = [ 00 00 00 00 00 00 ];
++ interrupts = <4 0x8>;
++ interrupt-parent = < &ipic >;
++ phy-handle = < &phy0 >;
++ };
++
++ // USB ULPI1
++ usb@3000 {
++ device_type = "usb";
++ compatible = "fsl-usb2-dr";
++ reg = <0x3000 0x400>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ interrupt-parent = < &ipic >;
++ interrupts = <43 0x8>;
++ dr_mode = "host";
++ phy_type = "ulpi";
++ big-endian-regs;
++ };
++
++ // USB ULPI2
++ //usb@4000 {
++ // device_type = "usb";
++ // compatible = "fsl-usb2-dr";
++ // reg = <0x4000 0x400>;
++ // #address-cells = <1>;
++ // #size-cells = <0>;
++ // interrupt-parent = < &ipic >;
++ // interrupts = <44 0x8>;
++ // dr_mode = "otg";
++ // phy_type = "ulpi";
++ // big-endian-regs;
++ //};
++
++ // Second FEC is not yet supported
++ //mdio@4800 {
++ // device_type = "mdio";
++ // compatible = "fsl,mpc5121-fec-mdio";
++ // reg = <0x4800 0x800>;
++ // #address-cells = <1>;
++ // #size-cells = <0>;
++ // phy1: ethernet-phy@0 {
++ // reg = <1>;
++ // device_type = "ethernet-phy";
++ // };
++ //};
++
++ //ethernet@4800 {
++ // device_type = "network";
++ // compatible = "fsl,mpc5121-fec";
++ // reg = <0x4800 0x800>;
++ // local-mac-address = [ 00 00 00 00 00 00 ];
++ // interrupts = <5 0x8>;
++ // interrupt-parent = < &ipic >;
++ // phy-handle = < &phy1 >;
++ //};
++
++ // IO control
++ ioctl@a000 {
++ compatible = "fsl,mpc5125-ioctl";
++ reg = <0xA000 0x1000>;
++ };
++ // PSC0 in ac97 mode
++ ac97@11000 {
++ device_type = "sound";
++ compatible = "fsl,mpc5125-psc-ac97", "fsl,mpc5125-psc";
++ cell-index = <0>;
++ reg = <0x11000 0x100>;
++ interrupts = <40 0x8>;
++ interrupt-parent = < &ipic >;
++ fsl,mode = "ac97-slave";
++ rx-fifo-size = <384>;
++ tx-fifo-size = <384>;
++ };
++ // 5125 PSCs are not 52xx or 5121 PSC compatible
++ // PSC1 uart0 aka ttyPSC0
++ serial@11100 {
++ device_type = "serial";
++ compatible = "fsl,mpc5125-psc-uart", "fsl,mpc5125-psc";
++ port-number = <0>;
++ cell-index = <1>;
++ reg = <0x11100 0x100>;
++ interrupts = <40 0x8 71 0x8>;
++ interrupt-parent = < &ipic >;
++ rx-fifo-size = <16>;
++ tx-fifo-size = <16>;
++ nodcd;
++ };
++
++ // PSC9 uart1 aka ttyPSC1
++ serial@11900 {
++ device_type = "serial";
++ compatible = "fsl,mpc5125-psc-uart", "fsl,mpc5125-psc";
++ port-number = <1>;
++ cell-index = <9>;
++ reg = <0x11900 0x100>;
++ interrupts = <40 0x8 32 0x8>;
++ interrupt-parent = < &ipic >;
++ rx-fifo-size = <16>;
++ tx-fifo-size = <16>;
++ nodcd;
++ };
++
++ pscfifo@11f00 {
++ compatible = "fsl,mpc5121-psc-fifo";
++ reg = <0x11f00 0x100>;
++ interrupts = <40 0x8>;
++ interrupt-parent = < &ipic >;
++ };
++
++ dma2@14000 {
++ compatible = "mpc512x-dma2";
++ reg = <0x14000 0x1800>;
++ interrupts = <65 0x8>;
++ interrupt-parent = < &ipic >;
++ };
++
++ };
++};
+diff -Naur linux-2.6.29/arch/powerpc/boot/dts/mpc5125-twr-fec2.dts linux-2.6.29-v2010041601/arch/powerpc/boot/dts/mpc5125-twr-fec2.dts
+--- linux-2.6.29/arch/powerpc/boot/dts/mpc5125-twr-fec2.dts 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/boot/dts/mpc5125-twr-fec2.dts 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,423 @@
++/*
++ * STx/Freescale ADS5125 MPC5125 silicon
++ *
++ * Copyright (C) 2009 Freescale Semiconductor Inc. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++/dts-v1/;
++
++/ {
++ model = "mpc5125ads";
++ compatible = "fsl,mpc5125ads";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ PowerPC,5125@0 {
++ device_type = "cpu";
++ reg = <0>;
++ d-cache-line-size = <0x20>; // 32 bytes
++ i-cache-line-size = <0x20>; // 32 bytes
++ d-cache-size = <0x8000>; // L1, 32K
++ i-cache-size = <0x8000>; // L1, 32K
++ timebase-frequency = <49500000>;// 49.5 MHz (csb/4)
++ bus-frequency = <198000000>; // 198 MHz csb bus
++ clock-frequency = <396000000>; // 396 MHz ppc core
++ };
++ };
++
++ memory {
++ device_type = "memory";
++ reg = <0x00000000 0x10000000>; // 256MB at 0
++ };
++
++ sram@30000000 {
++ compatible = "fsl,mpc5121-sram";
++ reg = <0x30000000 0x08000>; // 32K at 0x30000000
++ };
++
++ nfc@40000000 {
++ compatible = "fsl,mpc5125-nfc";
++ reg = <0x40000000 0x100000>; // 1M at 0x40000000
++ interrupts = <6 0x8>;
++ interrupt-parent = < &ipic >;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ bank-width = <1>;
++ write-size = <4096>;
++ spare-size = <218>;
++ chips = <1>;
++ nand-loader@0 {
++ label = "loader";
++ reg = <0x000000000 0x00100000>;
++ };
++ nand-uboot@100000 {
++ label = "uboot";
++ reg = <0x00100000 0x00100000>;
++ };
++ nand-envirement@200000 {
++ label = "envirment";
++ reg = <0x00200000 0x00100000>;
++ read-only;
++ };
++ nand-kernel@300000 {
++ label = "kernel";
++ reg = <0x00300000 0x00800000>;
++ };
++ devicetree@b00000 {
++ label = "device-tree";
++ reg = <0x00b00000 0x00100000>;
++ };
++ rootfs@c00000 {
++ label = "rootfs";
++ reg = <0x00c00000 0x00800000>;
++ };
++ filesystem@1000000 {
++ label = "filesystem";
++ reg = <0x01400000 0x7ec00000>;
++ };
++/*
++ data@80000000 {
++ label = "data";
++ reg = <0x80000000 0x7f000000>;
++ };
++*/
++ };
++
++/*
++ localbus@80000020 {
++ compatible = "fsl,mpc5121ads-localbus";
++ #address-cells = <2>;
++ #size-cells = <1>;
++ reg = <0x80000020 0x40>;
++
++ ranges = <0x0 0x0 0xfe000000 0x02000000
++ 0x2 0x0 0x82000000 0x00008000>;
++
++ flash@0,0 {
++ compatible = "cfi-flash";
++ reg = <0 0x0 0x2000000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ bank-width = <2>;
++ device-width = <2>;
++ protected@0 {
++ label = "protected";
++ reg = <0x00000000 0x00040000>; // first sector is protected
++ read-only;
++ };
++ filesystem@40000 {
++ label = "filesystem";
++ reg = <0x00040000 0x01a80000>; // 26.25M for filesystem
++ };
++ kernel@1c40000 {
++ label = "kernel";
++ reg = <0x01ac0000 0x00400000>; // 4M for kernel
++ };
++ device-tree@1ec0000 {
++ label = "device-tree";
++ reg = <0x01ec0000 0x00040000>; // one sector for device tree
++ };
++ u-boot@1f00000 {
++ label = "u-boot";
++ reg = <0x01f00000 0x00100000>; // 1M for u-boot
++ read-only;
++ };
++ };
++ };
++*/
++ soc@80000000 {
++ compatible = "fsl,mpc5121-immr";
++ device_type = "soc";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ #interrupt-cells = <2>;
++ ranges = <0x0 0x80000000 0x400000>;
++ reg = <0x80000000 0x400000>;
++ bus-frequency = <66000000>; // 66 MHz ips bus
++
++
++ // IPIC
++ // interrupts cell = <intr #, sense>
++ // sense values match linux IORESOURCE_IRQ_* defines:
++ // sense == 8: Level, low assertion
++ // sense == 2: Edge, high-to-low change
++ //
++ ipic: interrupt-controller@c00 {
++ compatible = "fsl,mpc5121-ipic", "fsl,ipic";
++ interrupt-controller;
++ #address-cells = <0>;
++ #interrupt-cells = <2>;
++ reg = <0xc00 0x100>;
++ };
++
++ rtc@a00 { // Real time clock
++ compatible = "fsl,mpc5121-rtc";
++ reg = <0xa00 0x100>;
++ interrupts = <79 0x8 80 0x8>;
++ interrupt-parent = < &ipic >;
++ };
++
++ reset@e00 { // Reset module
++ compatible = "fsl,mpc5121-reset";
++ reg = <0xe00 0x100>;
++ };
++
++ clock@f00 { // Clock control
++ compatible = "fsl,mpc5121rev2-clock", "fsl,mpc5121-clock";
++ reg = <0xf00 0x100>;
++ };
++
++ pmc@1000{ //Power Management Controller
++ compatible = "fsl,mpc5121-pmc";
++ reg = <0x1000 0x100>;
++ interrupts = <83 0x2>;
++ interrupt-parent = < &ipic >;
++ };
++
++ gpio@1100 {
++ compatible = "fsl,mpc5125-gpio";
++ cell-index = <0>;
++ reg = <0x1100 0x080>;
++ interrupts = <78 0x8>;
++ interrupt-parent = < &ipic >;
++ };
++
++ gpio@1180 {
++ compatible = "fsl,mpc5125-gpio1";
++ cell-index = <1>;
++ reg = <0x1180 0x080>;
++ interrupts = <78 0x8>;
++ interrupt-parent = < &ipic >;
++ };
++
++ mscan@1300 {
++ compatible = "fsl,mpc5121rev2-mscan";
++ cell-index = <0>;
++ interrupts = <12 0x8>;
++ interrupt-parent = < &ipic >;
++ reg = <0x1300 0x80>;
++ };
++
++ mscan@1380 {
++ compatible = "fsl,mpc5121rev2-mscan";
++ cell-index = <1>;
++ interrupts = <13 0x8>;
++ interrupt-parent = < &ipic >;
++ reg = <0x1380 0x80>;
++ };
++
++ sdhc@1500 {
++ compatible = "fsl,mpc5125-sdhc";
++ interrupts = <8 0x8>;
++ interrupt-parent = < &ipic >;
++ reg = <0x1500 0x100>;
++ };
++
++ i2c@1700 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "fsl-i2c";
++ cell-index = <0>;
++ reg = <0x1700 0x20>;
++ interrupts = <0x9 0x8>;
++ interrupt-parent = < &ipic >;
++ fsl5200-clocking;
++ };
++
++ i2c@1720 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "fsl-i2c";
++ cell-index = <1>;
++ reg = <0x1720 0x20>;
++ interrupts = <0xa 0x8>;
++ interrupt-parent = < &ipic >;
++ fsl5200-clocking;
++ };
++
++ i2c@1740 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "fsl-i2c";
++ cell-index = <2>;
++ reg = <0x1740 0x20>;
++ interrupts = <0xb 0x8>;
++ interrupt-parent = < &ipic >;
++ fsl5200-clocking;
++ };
++
++ i2ccontrol@1760 {
++ compatible = "fsl,mpc5121-i2c-ctrl";
++ reg = <0x1760 0x8>;
++ };
++
++ diu@2100 {
++ device_type = "display";
++ compatible = "fsl-diu";
++ reg = <0x2100 0x100>;
++ interrupts = <64 0x8>;
++ interrupt-parent = < &ipic >;
++ };
++
++ // MPC5125e has two more CAN ports
++ // but they are not used on ADS5125
++ //mscan@2300 {
++ // compatible = "fsl,mpc5121rev2-mscan";
++ // cell-index = <2>;
++ // interrupts = <90 0x8>;
++ // interrupt-parent = < &ipic >;
++ // reg = <0x2300 0x80>;
++ //};
++
++ //mscan@2380 {
++ // compatible = "fsl,mpc5121rev2-mscan";
++ // cell-index = <3>;
++ // interrupts = <91 0x8>;
++ // interrupt-parent = < &ipic >;
++ // reg = <0x2380 0x80>;
++ //};
++
++ mdio@2800 {
++ device_type = "mdio";
++ compatible = "fsl,mpc5121-fec-mdio";
++ reg = <0x2800 0x800>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ phy0: ethernet-phy@0 {
++ reg = <1>;
++ device_type = "ethernet-phy";
++ };
++ };
++
++ ethernet@2800 {
++ device_type = "network";
++ compatible = "fsl,mpc5121-fec";
++ reg = <0x2800 0x800>;
++ local-mac-address = [ 00 00 00 00 00 00 ];
++ interrupts = <4 0x8>;
++ interrupt-parent = < &ipic >;
++ phy-handle = < &phy0 >;
++ };
++
++ // USB ULPI1
++ usb@3000 {
++ device_type = "usb";
++ compatible = "fsl-usb2-dr";
++ reg = <0x3000 0x400>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ interrupt-parent = < &ipic >;
++ interrupts = <43 0x8>;
++ dr_mode = "host";
++ phy_type = "ulpi";
++ big-endian-regs;
++ };
++
++ // USB ULPI2
++ //usb@4000 {
++ // device_type = "usb";
++ // compatible = "fsl-usb2-dr";
++ // reg = <0x4000 0x400>;
++ // #address-cells = <1>;
++ // #size-cells = <0>;
++ // interrupt-parent = < &ipic >;
++ // interrupts = <44 0x8>;
++ // dr_mode = "otg";
++ // phy_type = "ulpi";
++ // big-endian-regs;
++ //};
++
++ // Second FEC is not yet supported
++ mdio@4800 {
++ device_type = "mdio";
++ compatible = "fsl,mpc5121-fec-mdio";
++ reg = <0x4800 0x800>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ phy1: ethernet-phy@0 {
++ reg = <1>;
++ device_type = "ethernet-phy";
++ };
++ };
++
++ ethernet@4800 {
++ device_type = "network";
++ compatible = "fsl,mpc5121-fec";
++ reg = <0x4800 0x800>;
++ local-mac-address = [ 00 00 00 00 00 00 ];
++ interrupts = <5 0x8>;
++ interrupt-parent = < &ipic >;
++ phy-handle = < &phy1 >;
++ };
++
++ // IO control
++ ioctl@a000 {
++ compatible = "fsl,mpc5125-ioctl";
++ reg = <0xA000 0x1000>;
++ };
++ // PSC0 in ac97 mode
++ ac97@11000 {
++ device_type = "sound";
++ compatible = "fsl,mpc5125-psc-ac97", "fsl,mpc5125-psc";
++ cell-index = <0>;
++ reg = <0x11000 0x100>;
++ interrupts = <40 0x8>;
++ interrupt-parent = < &ipic >;
++ fsl,mode = "ac97-slave";
++ rx-fifo-size = <384>;
++ tx-fifo-size = <384>;
++ };
++ // 5125 PSCs are not 52xx or 5121 PSC compatible
++ // PSC1 uart0 aka ttyPSC0
++ serial@11100 {
++ device_type = "serial";
++ compatible = "fsl,mpc5125-psc-uart", "fsl,mpc5125-psc";
++ port-number = <0>;
++ cell-index = <1>;
++ reg = <0x11100 0x100>;
++ interrupts = <40 0x8 71 0x8>;
++ interrupt-parent = < &ipic >;
++ rx-fifo-size = <16>;
++ tx-fifo-size = <16>;
++ nodcd;
++ };
++
++ // PSC9 uart1 aka ttyPSC1
++ serial@11900 {
++ device_type = "serial";
++ compatible = "fsl,mpc5125-psc-uart", "fsl,mpc5125-psc";
++ port-number = <1>;
++ cell-index = <9>;
++ reg = <0x11900 0x100>;
++ interrupts = <40 0x8 32 0x8>;
++ interrupt-parent = < &ipic >;
++ rx-fifo-size = <16>;
++ tx-fifo-size = <16>;
++ nodcd;
++ };
++
++ pscfifo@11f00 {
++ compatible = "fsl,mpc5121-psc-fifo";
++ reg = <0x11f00 0x100>;
++ interrupts = <40 0x8>;
++ interrupt-parent = < &ipic >;
++ };
++
++ dma2@14000 {
++ compatible = "mpc512x-dma2";
++ reg = <0x14000 0x1800>;
++ interrupts = <65 0x8>;
++ interrupt-parent = < &ipic >;
++ };
++
++ };
++};
+diff -Naur linux-2.6.29/arch/powerpc/configs/mpc5125_twr_defconfig linux-2.6.29-v2010041601/arch/powerpc/configs/mpc5125_twr_defconfig
+--- linux-2.6.29/arch/powerpc/configs/mpc5125_twr_defconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/configs/mpc5125_twr_defconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,2274 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.29.1
++# Thu Mar 18 13:38:38 2010
++#
++# CONFIG_PPC64 is not set
++
++#
++# Processor support
++#
++CONFIG_6xx=y
++# CONFIG_PPC_85xx is not set
++# CONFIG_PPC_8xx is not set
++# CONFIG_40x is not set
++# CONFIG_44x is not set
++# CONFIG_E200 is not set
++CONFIG_PPC_FPU=y
++# CONFIG_ALTIVEC is not set
++CONFIG_PPC_STD_MMU=y
++CONFIG_PPC_STD_MMU_32=y
++# CONFIG_PPC_MM_SLICES is not set
++# CONFIG_SMP is not set
++CONFIG_NOT_COHERENT_CACHE=y
++CONFIG_PPC32=y
++CONFIG_WORD_SIZE=32
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_MMU=y
++CONFIG_GENERIC_CMOS_UPDATE=y
++CONFIG_GENERIC_TIME=y
++CONFIG_GENERIC_TIME_VSYSCALL=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_HARDIRQS=y
++# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
++CONFIG_IRQ_PER_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_ARCH_HAS_ILOG2_U32=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
++CONFIG_PPC=y
++CONFIG_EARLY_PRINTK=y
++CONFIG_GENERIC_NVRAM=y
++CONFIG_SCHED_OMIT_FRAME_POINTER=y
++CONFIG_ARCH_MAY_HAVE_PC_FDC=y
++CONFIG_PPC_OF=y
++CONFIG_OF=y
++CONFIG_PPC_UDBG_16550=y
++# CONFIG_GENERIC_TBSYNC is not set
++CONFIG_AUDIT_ARCH=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFAULT_UIMAGE=y
++# CONFIG_PPC_DCR_NATIVE is not set
++# CONFIG_PPC_DCR_MMIO is not set
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++CONFIG_TASKSTATS=y
++CONFIG_TASK_DELAY_ACCT=y
++CONFIG_TASK_XACCT=y
++CONFIG_TASK_IO_ACCOUNTING=y
++CONFIG_AUDIT=y
++CONFIG_AUDITSYSCALL=y
++CONFIG_AUDIT_TREE=y
++
++#
++# RCU Subsystem
++#
++CONFIG_CLASSIC_RCU=y
++# CONFIG_TREE_RCU is not set
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_PREEMPT_RCU_TRACE is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_GROUP_SCHED=y
++CONFIG_FAIR_GROUP_SCHED=y
++# CONFIG_RT_GROUP_SCHED is not set
++# CONFIG_USER_SCHED is not set
++CONFIG_CGROUP_SCHED=y
++CONFIG_CGROUPS=y
++# CONFIG_CGROUP_DEBUG is not set
++CONFIG_CGROUP_NS=y
++CONFIG_CGROUP_FREEZER=y
++CONFIG_CGROUP_DEVICE=y
++CONFIG_CGROUP_CPUACCT=y
++# CONFIG_RESOURCE_COUNTERS is not set
++# CONFIG_SYSFS_DEPRECATED_V2 is not set
++CONFIG_RELAY=y
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++# CONFIG_EMBEDDED is not set
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_PCSPKR_PLATFORM=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_PCI_QUIRKS=y
++# CONFIG_COMPAT_BRK is not set
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++CONFIG_TRACEPOINTS=y
++CONFIG_MARKERS=y
++CONFIG_OPROFILE=m
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_HAVE_IOREMAP_PROT=y
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_ARCH_TRACEHOOK=y
++CONFIG_HAVE_CLK=y
++# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++CONFIG_MODULE_FORCE_LOAD=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODULE_FORCE_UNLOAD=y
++CONFIG_MODVERSIONS=y
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBD=y
++CONFIG_BLK_DEV_IO_TRACE=y
++CONFIG_BLK_DEV_BSG=y
++CONFIG_BLK_DEV_INTEGRITY=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_AS=y
++# CONFIG_DEFAULT_DEADLINE is not set
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="anticipatory"
++CONFIG_FREEZER=y
++
++#
++# Platform support
++#
++CONFIG_PPC_MULTIPLATFORM=y
++CONFIG_CLASSIC32=y
++CONFIG_PPC_CHRP=y
++CONFIG_PPC_MPC512x=y
++CONFIG_PPC_MPC5125=y
++# CONFIG_PPC_MPC5121 is not set
++# CONFIG_MPC5121_ADS is not set
++CONFIG_PPC_MERGE=y
++CONFIG_MPC5125_TWR=y
++# CONFIG_MPC5121_GENERIC is not set
++# CONFIG_MPC5121_ADS_HIB is not set
++CONFIG_MPC5121_PM_TEST=y
++# CONFIG_PPC_MPC52xx is not set
++# CONFIG_PPC_PMAC is not set
++# CONFIG_PPC_CELL is not set
++# CONFIG_PPC_CELL_NATIVE is not set
++# CONFIG_PPC_82xx is not set
++# CONFIG_PQ2ADS is not set
++# CONFIG_PPC_83xx is not set
++# CONFIG_PPC_86xx is not set
++# CONFIG_EMBEDDED6xx is not set
++CONFIG_PPC_NATIVE=y
++# CONFIG_UDBG_RTAS_CONSOLE is not set
++CONFIG_IPIC=y
++CONFIG_MPIC=y
++# CONFIG_MPIC_WEIRD is not set
++CONFIG_PPC_I8259=y
++CONFIG_PPC_RTAS=y
++# CONFIG_RTAS_ERROR_LOGGING is not set
++# CONFIG_RTAS_PROC is not set
++# CONFIG_MMIO_NVRAM is not set
++CONFIG_PPC_MPC106=y
++# CONFIG_PPC_970_NAP is not set
++# CONFIG_PPC_INDIRECT_IO is not set
++# CONFIG_GENERIC_IOMAP is not set
++# CONFIG_CPU_FREQ is not set
++# CONFIG_TAU is not set
++# CONFIG_QUICC_ENGINE is not set
++# CONFIG_FSL_ULI1575 is not set
++# CONFIG_SIMPLE_GPIO is not set
++
++#
++# Kernel options
++#
++# CONFIG_HIGHMEM is not set
++CONFIG_ARCH_HIBERNATION_POSSIBLE=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_TICK_ONESHOT=y
++# CONFIG_NO_HZ is not set
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_HZ_100 is not set
++CONFIG_HZ_250=y
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=250
++CONFIG_SCHED_HRTICK=y
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_BINFMT_ELF=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_IOMMU_HELPER is not set
++CONFIG_PPC_NEED_DMA_SYNC_OPS=y
++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
++CONFIG_ARCH_HAS_WALK_MEMORY=y
++CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
++CONFIG_KEXEC=y
++# CONFIG_CRASH_DUMP is not set
++CONFIG_ARCH_FLATMEM_ENABLE=y
++CONFIG_ARCH_POPULATES_NODE_MAP=y
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_MIGRATION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=1
++CONFIG_BOUNCE=y
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_UNEVICTABLE_LRU is not set
++CONFIG_PPC_4K_PAGES=y
++# CONFIG_PPC_16K_PAGES is not set
++# CONFIG_PPC_64K_PAGES is not set
++CONFIG_FORCE_MAX_ZONEORDER=11
++CONFIG_PROC_DEVICETREE=y
++# CONFIG_CMDLINE_BOOL is not set
++CONFIG_EXTRA_TARGETS=""
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_HIBERNATION is not set
++CONFIG_SECCOMP=y
++CONFIG_ISA_DMA_API=y
++
++#
++# Bus options
++#
++# CONFIG_ISA is not set
++CONFIG_ZONE_DMA=y
++CONFIG_GENERIC_ISA_DMA=y
++CONFIG_PPC_INDIRECT_PCI=y
++CONFIG_FSL_SOC=y
++CONFIG_FSL_PCI=y
++CONFIG_PPC_PCI_CHOICE=y
++CONFIG_PCI=y
++CONFIG_PCI_DOMAINS=y
++CONFIG_PCI_SYSCALL=y
++# CONFIG_PCIEPORTBUS is not set
++CONFIG_ARCH_SUPPORTS_MSI=y
++# CONFIG_PCI_MSI is not set
++CONFIG_PCI_LEGACY=y
++# CONFIG_PCI_STUB is not set
++# CONFIG_PCCARD is not set
++# CONFIG_HOTPLUG_PCI is not set
++# CONFIG_HAS_RAPIDIO is not set
++
++#
++# Advanced setup
++#
++CONFIG_ADVANCED_OPTIONS=y
++# CONFIG_LOWMEM_SIZE_BOOL is not set
++CONFIG_LOWMEM_SIZE=0x30000000
++CONFIG_AXEMBX_RESERVE_BOOL=y
++CONFIG_AXEMBX_RESERVE_START=0x00400000
++CONFIG_AXE_RESERVE_SIZE=0x00100000
++CONFIG_MBX_RESERVE_SIZE=0x0
++# CONFIG_PAGE_OFFSET_BOOL is not set
++CONFIG_PAGE_OFFSET=0xc0000000
++# CONFIG_KERNEL_START_BOOL is not set
++CONFIG_KERNEL_START=0xc0000000
++CONFIG_PHYSICAL_START=0x00000000
++# CONFIG_TASK_SIZE_BOOL is not set
++CONFIG_TASK_SIZE=0xc0000000
++# CONFIG_CONSISTENT_START_BOOL is not set
++CONFIG_CONSISTENT_START=0xff100000
++# CONFIG_CONSISTENT_SIZE_BOOL is not set
++CONFIG_CONSISTENT_SIZE=0x00200000
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_COMPAT_NET_DEV_OPS=y
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++CONFIG_XFRM_USER=m
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++CONFIG_XFRM_IPCOMP=m
++CONFIG_NET_KEY=m
++# CONFIG_NET_KEY_MIGRATE is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++CONFIG_SYN_COOKIES=y
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++CONFIG_INET_TUNNEL=m
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++CONFIG_TCP_CONG_ADVANCED=y
++CONFIG_TCP_CONG_BIC=m
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_TCP_CONG_WESTWOOD=m
++CONFIG_TCP_CONG_HTCP=m
++CONFIG_TCP_CONG_HSTCP=m
++CONFIG_TCP_CONG_HYBLA=m
++CONFIG_TCP_CONG_VEGAS=m
++CONFIG_TCP_CONG_SCALABLE=m
++CONFIG_TCP_CONG_LP=m
++CONFIG_TCP_CONG_VENO=m
++CONFIG_TCP_CONG_YEAH=m
++CONFIG_TCP_CONG_ILLINOIS=m
++# CONFIG_DEFAULT_BIC is not set
++CONFIG_DEFAULT_CUBIC=y
++# CONFIG_DEFAULT_HTCP is not set
++# CONFIG_DEFAULT_VEGAS is not set
++# CONFIG_DEFAULT_WESTWOOD is not set
++# CONFIG_DEFAULT_RENO is not set
++CONFIG_DEFAULT_TCP_CONG="cubic"
++CONFIG_TCP_MD5SIG=y
++CONFIG_IPV6=m
++CONFIG_IPV6_PRIVACY=y
++CONFIG_IPV6_ROUTER_PREF=y
++CONFIG_IPV6_ROUTE_INFO=y
++CONFIG_IPV6_OPTIMISTIC_DAD=y
++CONFIG_INET6_AH=m
++CONFIG_INET6_ESP=m
++CONFIG_INET6_IPCOMP=m
++CONFIG_IPV6_MIP6=m
++CONFIG_INET6_XFRM_TUNNEL=m
++CONFIG_INET6_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_TRANSPORT=m
++CONFIG_INET6_XFRM_MODE_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_BEET=m
++CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
++CONFIG_IPV6_SIT=m
++CONFIG_IPV6_NDISC_NODETYPE=y
++CONFIG_IPV6_TUNNEL=m
++CONFIG_IPV6_MULTIPLE_TABLES=y
++CONFIG_IPV6_SUBTREES=y
++CONFIG_IPV6_MROUTE=y
++CONFIG_IPV6_PIMSM_V2=y
++CONFIG_NETWORK_SECMARK=y
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_NETFILTER_ADVANCED=y
++CONFIG_BRIDGE_NETFILTER=y
++
++#
++# Core Netfilter Configuration
++#
++CONFIG_NETFILTER_NETLINK=m
++CONFIG_NETFILTER_NETLINK_QUEUE=m
++CONFIG_NETFILTER_NETLINK_LOG=m
++CONFIG_NF_CONNTRACK=m
++CONFIG_NF_CT_ACCT=y
++CONFIG_NF_CONNTRACK_MARK=y
++CONFIG_NF_CONNTRACK_SECMARK=y
++CONFIG_NF_CONNTRACK_EVENTS=y
++CONFIG_NF_CT_PROTO_DCCP=m
++CONFIG_NF_CT_PROTO_GRE=m
++CONFIG_NF_CT_PROTO_SCTP=m
++CONFIG_NF_CT_PROTO_UDPLITE=m
++CONFIG_NF_CONNTRACK_AMANDA=m
++CONFIG_NF_CONNTRACK_FTP=m
++CONFIG_NF_CONNTRACK_H323=m
++CONFIG_NF_CONNTRACK_IRC=m
++CONFIG_NF_CONNTRACK_NETBIOS_NS=m
++CONFIG_NF_CONNTRACK_PPTP=m
++CONFIG_NF_CONNTRACK_SANE=m
++CONFIG_NF_CONNTRACK_SIP=m
++CONFIG_NF_CONNTRACK_TFTP=m
++CONFIG_NF_CT_NETLINK=m
++CONFIG_NETFILTER_TPROXY=m
++CONFIG_NETFILTER_XTABLES=m
++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
++CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
++CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
++CONFIG_NETFILTER_XT_TARGET_DSCP=m
++CONFIG_NETFILTER_XT_TARGET_MARK=m
++CONFIG_NETFILTER_XT_TARGET_NFLOG=m
++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
++CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
++CONFIG_NETFILTER_XT_TARGET_RATEEST=m
++CONFIG_NETFILTER_XT_TARGET_TPROXY=m
++CONFIG_NETFILTER_XT_TARGET_TRACE=m
++CONFIG_NETFILTER_XT_TARGET_SECMARK=m
++CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
++CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
++CONFIG_NETFILTER_XT_MATCH_COMMENT=m
++CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
++CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
++CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
++CONFIG_NETFILTER_XT_MATCH_DCCP=m
++CONFIG_NETFILTER_XT_MATCH_DSCP=m
++CONFIG_NETFILTER_XT_MATCH_ESP=m
++CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
++CONFIG_NETFILTER_XT_MATCH_HELPER=m
++CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
++CONFIG_NETFILTER_XT_MATCH_LENGTH=m
++CONFIG_NETFILTER_XT_MATCH_LIMIT=m
++CONFIG_NETFILTER_XT_MATCH_MAC=m
++CONFIG_NETFILTER_XT_MATCH_MARK=m
++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
++CONFIG_NETFILTER_XT_MATCH_OWNER=m
++CONFIG_NETFILTER_XT_MATCH_POLICY=m
++CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
++CONFIG_NETFILTER_XT_MATCH_QUOTA=m
++CONFIG_NETFILTER_XT_MATCH_RATEEST=m
++CONFIG_NETFILTER_XT_MATCH_REALM=m
++CONFIG_NETFILTER_XT_MATCH_RECENT=m
++# CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT is not set
++CONFIG_NETFILTER_XT_MATCH_SCTP=m
++CONFIG_NETFILTER_XT_MATCH_SOCKET=m
++CONFIG_NETFILTER_XT_MATCH_STATE=m
++CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
++CONFIG_NETFILTER_XT_MATCH_STRING=m
++CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
++CONFIG_NETFILTER_XT_MATCH_TIME=m
++CONFIG_NETFILTER_XT_MATCH_U32=m
++CONFIG_IP_VS=m
++# CONFIG_IP_VS_IPV6 is not set
++# CONFIG_IP_VS_DEBUG is not set
++CONFIG_IP_VS_TAB_BITS=12
++
++#
++# IPVS transport protocol load balancing support
++#
++CONFIG_IP_VS_PROTO_TCP=y
++CONFIG_IP_VS_PROTO_UDP=y
++CONFIG_IP_VS_PROTO_AH_ESP=y
++CONFIG_IP_VS_PROTO_ESP=y
++CONFIG_IP_VS_PROTO_AH=y
++
++#
++# IPVS scheduler
++#
++CONFIG_IP_VS_RR=m
++CONFIG_IP_VS_WRR=m
++CONFIG_IP_VS_LC=m
++CONFIG_IP_VS_WLC=m
++CONFIG_IP_VS_LBLC=m
++CONFIG_IP_VS_LBLCR=m
++CONFIG_IP_VS_DH=m
++CONFIG_IP_VS_SH=m
++CONFIG_IP_VS_SED=m
++CONFIG_IP_VS_NQ=m
++
++#
++# IPVS application helper
++#
++CONFIG_IP_VS_FTP=m
++
++#
++# IP: Netfilter Configuration
++#
++CONFIG_NF_DEFRAG_IPV4=m
++CONFIG_NF_CONNTRACK_IPV4=m
++CONFIG_NF_CONNTRACK_PROC_COMPAT=y
++CONFIG_IP_NF_QUEUE=m
++CONFIG_IP_NF_IPTABLES=m
++CONFIG_IP_NF_MATCH_ADDRTYPE=m
++CONFIG_IP_NF_MATCH_AH=m
++CONFIG_IP_NF_MATCH_ECN=m
++CONFIG_IP_NF_MATCH_TTL=m
++CONFIG_IP_NF_FILTER=m
++CONFIG_IP_NF_TARGET_REJECT=m
++CONFIG_IP_NF_TARGET_LOG=m
++CONFIG_IP_NF_TARGET_ULOG=m
++CONFIG_NF_NAT=m
++CONFIG_NF_NAT_NEEDED=y
++CONFIG_IP_NF_TARGET_MASQUERADE=m
++CONFIG_IP_NF_TARGET_NETMAP=m
++CONFIG_IP_NF_TARGET_REDIRECT=m
++CONFIG_NF_NAT_SNMP_BASIC=m
++CONFIG_NF_NAT_PROTO_DCCP=m
++CONFIG_NF_NAT_PROTO_GRE=m
++CONFIG_NF_NAT_PROTO_UDPLITE=m
++CONFIG_NF_NAT_PROTO_SCTP=m
++CONFIG_NF_NAT_FTP=m
++CONFIG_NF_NAT_IRC=m
++CONFIG_NF_NAT_TFTP=m
++CONFIG_NF_NAT_AMANDA=m
++CONFIG_NF_NAT_PPTP=m
++CONFIG_NF_NAT_H323=m
++CONFIG_NF_NAT_SIP=m
++CONFIG_IP_NF_MANGLE=m
++CONFIG_IP_NF_TARGET_CLUSTERIP=m
++CONFIG_IP_NF_TARGET_ECN=m
++CONFIG_IP_NF_TARGET_TTL=m
++CONFIG_IP_NF_RAW=m
++CONFIG_IP_NF_ARPTABLES=m
++CONFIG_IP_NF_ARPFILTER=m
++CONFIG_IP_NF_ARP_MANGLE=m
++
++#
++# IPv6: Netfilter Configuration
++#
++CONFIG_NF_CONNTRACK_IPV6=m
++CONFIG_IP6_NF_QUEUE=m
++CONFIG_IP6_NF_IPTABLES=m
++CONFIG_IP6_NF_MATCH_AH=m
++CONFIG_IP6_NF_MATCH_EUI64=m
++CONFIG_IP6_NF_MATCH_FRAG=m
++CONFIG_IP6_NF_MATCH_OPTS=m
++CONFIG_IP6_NF_MATCH_HL=m
++CONFIG_IP6_NF_MATCH_IPV6HEADER=m
++CONFIG_IP6_NF_MATCH_MH=m
++CONFIG_IP6_NF_MATCH_RT=m
++CONFIG_IP6_NF_TARGET_LOG=m
++CONFIG_IP6_NF_FILTER=m
++CONFIG_IP6_NF_TARGET_REJECT=m
++CONFIG_IP6_NF_MANGLE=m
++CONFIG_IP6_NF_TARGET_HL=m
++CONFIG_IP6_NF_RAW=m
++
++#
++# DECnet: Netfilter Configuration
++#
++CONFIG_DECNET_NF_GRABULATOR=m
++CONFIG_BRIDGE_NF_EBTABLES=m
++CONFIG_BRIDGE_EBT_BROUTE=m
++CONFIG_BRIDGE_EBT_T_FILTER=m
++CONFIG_BRIDGE_EBT_T_NAT=m
++CONFIG_BRIDGE_EBT_802_3=m
++CONFIG_BRIDGE_EBT_AMONG=m
++CONFIG_BRIDGE_EBT_ARP=m
++CONFIG_BRIDGE_EBT_IP=m
++CONFIG_BRIDGE_EBT_IP6=m
++CONFIG_BRIDGE_EBT_LIMIT=m
++CONFIG_BRIDGE_EBT_MARK=m
++CONFIG_BRIDGE_EBT_PKTTYPE=m
++CONFIG_BRIDGE_EBT_STP=m
++CONFIG_BRIDGE_EBT_VLAN=m
++CONFIG_BRIDGE_EBT_ARPREPLY=m
++CONFIG_BRIDGE_EBT_DNAT=m
++CONFIG_BRIDGE_EBT_MARK_T=m
++CONFIG_BRIDGE_EBT_REDIRECT=m
++CONFIG_BRIDGE_EBT_SNAT=m
++CONFIG_BRIDGE_EBT_LOG=m
++CONFIG_BRIDGE_EBT_ULOG=m
++CONFIG_BRIDGE_EBT_NFLOG=m
++CONFIG_IP_DCCP=m
++CONFIG_INET_DCCP_DIAG=m
++
++#
++# DCCP CCIDs Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP_CCID2_DEBUG is not set
++CONFIG_IP_DCCP_CCID3=y
++# CONFIG_IP_DCCP_CCID3_DEBUG is not set
++CONFIG_IP_DCCP_CCID3_RTO=100
++CONFIG_IP_DCCP_TFRC_LIB=y
++CONFIG_IP_SCTP=m
++# CONFIG_SCTP_DBG_MSG is not set
++# CONFIG_SCTP_DBG_OBJCNT is not set
++# CONFIG_SCTP_HMAC_NONE is not set
++# CONFIG_SCTP_HMAC_SHA1 is not set
++CONFIG_SCTP_HMAC_MD5=y
++CONFIG_TIPC=m
++CONFIG_TIPC_ADVANCED=y
++CONFIG_TIPC_ZONES=3
++CONFIG_TIPC_CLUSTERS=1
++CONFIG_TIPC_NODES=255
++CONFIG_TIPC_SLAVE_NODES=0
++CONFIG_TIPC_PORTS=8191
++CONFIG_TIPC_LOG=0
++# CONFIG_TIPC_DEBUG is not set
++CONFIG_ATM=m
++CONFIG_ATM_CLIP=m
++CONFIG_ATM_CLIP_NO_ICMP=y
++CONFIG_ATM_LANE=m
++CONFIG_ATM_MPOA=m
++CONFIG_ATM_BR2684=m
++# CONFIG_ATM_BR2684_IPFILTER is not set
++CONFIG_STP=m
++CONFIG_GARP=m
++CONFIG_BRIDGE=m
++# CONFIG_NET_DSA is not set
++CONFIG_VLAN_8021Q=m
++CONFIG_VLAN_8021Q_GVRP=y
++CONFIG_DECNET=m
++CONFIG_DECNET_ROUTER=y
++CONFIG_LLC=m
++CONFIG_LLC2=m
++CONFIG_IPX=m
++CONFIG_IPX_INTERN=y
++CONFIG_ATALK=m
++CONFIG_DEV_APPLETALK=m
++CONFIG_IPDDP=m
++CONFIG_IPDDP_ENCAP=y
++CONFIG_IPDDP_DECAP=y
++CONFIG_X25=m
++CONFIG_LAPB=m
++CONFIG_ECONET=m
++CONFIG_ECONET_AUNUDP=y
++CONFIG_ECONET_NATIVE=y
++CONFIG_WAN_ROUTER=m
++CONFIG_NET_SCHED=y
++
++#
++# Queueing/Scheduling
++#
++CONFIG_NET_SCH_CBQ=m
++CONFIG_NET_SCH_HTB=m
++CONFIG_NET_SCH_HFSC=m
++CONFIG_NET_SCH_ATM=m
++CONFIG_NET_SCH_PRIO=m
++CONFIG_NET_SCH_MULTIQ=m
++CONFIG_NET_SCH_RED=m
++CONFIG_NET_SCH_SFQ=m
++CONFIG_NET_SCH_TEQL=m
++CONFIG_NET_SCH_TBF=m
++CONFIG_NET_SCH_GRED=m
++CONFIG_NET_SCH_DSMARK=m
++CONFIG_NET_SCH_NETEM=m
++CONFIG_NET_SCH_DRR=m
++CONFIG_NET_SCH_INGRESS=m
++
++#
++# Classification
++#
++CONFIG_NET_CLS=y
++CONFIG_NET_CLS_BASIC=m
++CONFIG_NET_CLS_TCINDEX=m
++CONFIG_NET_CLS_ROUTE4=m
++CONFIG_NET_CLS_ROUTE=y
++CONFIG_NET_CLS_FW=m
++CONFIG_NET_CLS_U32=m
++CONFIG_CLS_U32_PERF=y
++CONFIG_CLS_U32_MARK=y
++CONFIG_NET_CLS_RSVP=m
++CONFIG_NET_CLS_RSVP6=m
++CONFIG_NET_CLS_FLOW=m
++CONFIG_NET_CLS_CGROUP=y
++CONFIG_NET_EMATCH=y
++CONFIG_NET_EMATCH_STACK=32
++CONFIG_NET_EMATCH_CMP=m
++CONFIG_NET_EMATCH_NBYTE=m
++CONFIG_NET_EMATCH_U32=m
++CONFIG_NET_EMATCH_META=m
++CONFIG_NET_EMATCH_TEXT=m
++CONFIG_NET_CLS_ACT=y
++CONFIG_NET_ACT_POLICE=m
++CONFIG_NET_ACT_GACT=m
++CONFIG_GACT_PROB=y
++CONFIG_NET_ACT_MIRRED=m
++CONFIG_NET_ACT_IPT=m
++CONFIG_NET_ACT_NAT=m
++CONFIG_NET_ACT_PEDIT=m
++CONFIG_NET_ACT_SIMP=m
++CONFIG_NET_ACT_SKBEDIT=m
++CONFIG_NET_CLS_IND=y
++CONFIG_NET_SCH_FIFO=y
++CONFIG_DCB=y
++
++#
++# Network testing
++#
++CONFIG_NET_PKTGEN=m
++# CONFIG_HAMRADIO is not set
++CONFIG_CAN=y
++CONFIG_CAN_RAW=y
++# CONFIG_CAN_BCM is not set
++
++#
++# CAN Device Drivers
++#
++CONFIG_CAN_VCAN=y
++# CONFIG_CAN_DEBUG_DEVICES is not set
++CONFIG_CAN_MSCAN=y
++CONFIG_CAN_MPC52XX=y
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++# CONFIG_PHONET is not set
++CONFIG_FIB_RULES=y
++# CONFIG_WIRELESS is not set
++# CONFIG_WIMAX is not set
++CONFIG_RFKILL=m
++CONFIG_RFKILL_INPUT=m
++# CONFIG_NET_9P is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_SYS_HYPERVISOR is not set
++CONFIG_CONNECTOR=m
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++CONFIG_MTD_OF_PARTS=y
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_MTD_OOPS 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 is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_OTP is not set
++# CONFIG_MTD_CFI_INTELEXT is not set
++CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_CFI_STAA is not set
++CONFIG_MTD_CFI_UTIL=y
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++CONFIG_MTD_COMPLEX_MAPPINGS=y
++# CONFIG_MTD_PHYSMAP is not set
++CONFIG_MTD_PHYSMAP_OF=y
++# CONFIG_MTD_PCI is not set
++# CONFIG_MTD_INTEL_VR_NOR is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_SMC is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_MPC5125_NFC=y
++CONFIG_MTD_NAND_FSL=y
++CONFIG_MTD_NAND_MPC5125_HARDWARE_ECC_CORRECTION=y
++# CONFIG_NFC_DMA_ENABLE is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_CAFE is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++# CONFIG_MTD_NAND_FSL_ELBC is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++
++#
++# UBI - Unsorted block images
++#
++# CONFIG_MTD_UBI is not set
++CONFIG_OF_DEVICE=y
++CONFIG_OF_I2C=m
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++CONFIG_BLK_DEV_FD=m
++CONFIG_BLK_CPQ_DA=m
++CONFIG_BLK_CPQ_CISS_DA=m
++CONFIG_CISS_SCSI_TAPE=y
++CONFIG_BLK_DEV_DAC960=m
++CONFIG_BLK_DEV_UMEM=m
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=m
++CONFIG_BLK_DEV_CRYPTOLOOP=m
++CONFIG_BLK_DEV_NBD=m
++CONFIG_BLK_DEV_SX8=m
++CONFIG_BLK_DEV_UB=y
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=4
++CONFIG_BLK_DEV_RAM_SIZE=32768
++# CONFIG_BLK_DEV_XIP is not set
++CONFIG_CDROM_PKTCDVD=m
++CONFIG_CDROM_PKTCDVD_BUFFERS=8
++# CONFIG_CDROM_PKTCDVD_WCACHE is not set
++CONFIG_ATA_OVER_ETH=m
++# CONFIG_BLK_DEV_HD is not set
++# CONFIG_MISC_DEVICES is not set
++CONFIG_TIFM_CORE=m
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++CONFIG_SCSI_TGT=m
++CONFIG_SCSI_NETLINK=y
++# CONFIG_SCSI_PROC_FS is not set
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++CONFIG_BLK_DEV_SR_VENDOR=y
++CONFIG_CHR_DEV_SG=y
++CONFIG_CHR_DEV_SCH=y
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++CONFIG_SCSI_MULTI_LUN=y
++CONFIG_SCSI_CONSTANTS=y
++CONFIG_SCSI_LOGGING=y
++CONFIG_SCSI_SCAN_ASYNC=y
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++CONFIG_SCSI_SPI_ATTRS=m
++CONFIG_SCSI_FC_ATTRS=m
++# CONFIG_SCSI_FC_TGT_ATTRS is not set
++CONFIG_SCSI_ISCSI_ATTRS=m
++CONFIG_SCSI_SAS_ATTRS=m
++CONFIG_SCSI_SAS_LIBSAS=m
++# CONFIG_SCSI_SAS_HOST_SMP is not set
++# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set
++CONFIG_SCSI_SRP_ATTRS=m
++# CONFIG_SCSI_SRP_TGT_ATTRS is not set
++CONFIG_SCSI_LOWLEVEL=y
++CONFIG_ISCSI_TCP=m
++CONFIG_BLK_DEV_3W_XXXX_RAID=m
++CONFIG_SCSI_3W_9XXX=m
++CONFIG_SCSI_ACARD=m
++CONFIG_SCSI_AACRAID=m
++CONFIG_SCSI_AIC7XXX=m
++CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
++CONFIG_AIC7XXX_RESET_DELAY_MS=15000
++CONFIG_AIC7XXX_DEBUG_ENABLE=y
++CONFIG_AIC7XXX_DEBUG_MASK=0
++CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
++CONFIG_SCSI_AIC7XXX_OLD=m
++CONFIG_SCSI_AIC79XX=m
++CONFIG_AIC79XX_CMDS_PER_DEVICE=32
++CONFIG_AIC79XX_RESET_DELAY_MS=15000
++CONFIG_AIC79XX_DEBUG_ENABLE=y
++CONFIG_AIC79XX_DEBUG_MASK=0
++CONFIG_AIC79XX_REG_PRETTY_PRINT=y
++CONFIG_SCSI_AIC94XX=m
++# CONFIG_AIC94XX_DEBUG is not set
++CONFIG_SCSI_DPT_I2O=m
++CONFIG_SCSI_ADVANSYS=m
++CONFIG_SCSI_ARCMSR=m
++CONFIG_MEGARAID_NEWGEN=y
++CONFIG_MEGARAID_MM=m
++CONFIG_MEGARAID_MAILBOX=m
++# CONFIG_MEGARAID_LEGACY is not set
++CONFIG_MEGARAID_SAS=m
++CONFIG_SCSI_HPTIOP=m
++CONFIG_SCSI_BUSLOGIC=m
++CONFIG_LIBFC=m
++CONFIG_FCOE=m
++CONFIG_SCSI_DMX3191D=m
++CONFIG_SCSI_EATA=m
++# CONFIG_SCSI_EATA_TAGGED_QUEUE is not set
++# CONFIG_SCSI_EATA_LINKED_COMMANDS is not set
++CONFIG_SCSI_EATA_MAX_TAGS=16
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_GDTH is not set
++CONFIG_SCSI_IPS=m
++# CONFIG_SCSI_INITIO is not set
++CONFIG_SCSI_INIA100=m
++CONFIG_SCSI_MVSAS=m
++CONFIG_SCSI_STEX=m
++CONFIG_SCSI_SYM53C8XX_2=m
++CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
++CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
++CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
++CONFIG_SCSI_SYM53C8XX_MMIO=y
++# CONFIG_SCSI_QLOGIC_1280 is not set
++CONFIG_SCSI_QLA_FC=m
++CONFIG_SCSI_QLA_ISCSI=m
++CONFIG_SCSI_LPFC=m
++# CONFIG_SCSI_LPFC_DEBUG_FS is not set
++CONFIG_SCSI_DC395x=m
++CONFIG_SCSI_DC390T=m
++CONFIG_SCSI_NSP32=m
++# CONFIG_SCSI_DEBUG is not set
++CONFIG_SCSI_SRP=m
++# CONFIG_SCSI_DH is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_FUSION is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++
++#
++# Enable only one of the two stacks, unless you know what you are doing
++#
++CONFIG_FIREWIRE=m
++CONFIG_FIREWIRE_OHCI=m
++CONFIG_FIREWIRE_OHCI_DEBUG=y
++CONFIG_FIREWIRE_SBP2=m
++# CONFIG_IEEE1394 is not set
++# CONFIG_I2O is not set
++# CONFIG_MACINTOSH_DRIVERS is not set
++CONFIG_NETDEVICES=y
++CONFIG_IFB=m
++CONFIG_DUMMY=m
++CONFIG_BONDING=m
++CONFIG_MACVLAN=m
++CONFIG_EQUALIZER=m
++CONFIG_TUN=m
++CONFIG_VETH=m
++CONFIG_ARCNET=m
++CONFIG_ARCNET_1201=m
++CONFIG_ARCNET_1051=m
++CONFIG_ARCNET_RAW=m
++CONFIG_ARCNET_CAP=m
++# CONFIG_ARCNET_COM90xx is not set
++CONFIG_ARCNET_COM90xxIO=m
++# CONFIG_ARCNET_RIM_I is not set
++CONFIG_ARCNET_COM20020=m
++CONFIG_ARCNET_COM20020_PCI=m
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_HAPPYMEAL is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_TULIP is not set
++# CONFIG_HP100 is not set
++# CONFIG_IBM_NEW_EMAC_ZMII is not set
++# CONFIG_IBM_NEW_EMAC_RGMII is not set
++# CONFIG_IBM_NEW_EMAC_TAH is not set
++# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
++# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
++# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
++# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_B44 is not set
++# CONFIG_ATL2 is not set
++CONFIG_FS_ENET=y
++CONFIG_FS_ENET_MPC5121_FEC=y
++# CONFIG_FS_ENET_MPC5125_FEC2 is not set
++CONFIG_FS_ENET_HAS_FEC=y
++CONFIG_FS_ENET_MDIO_FEC=y
++# CONFIG_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++CONFIG_MLX4_CORE=m
++# CONFIG_TR is not set
++
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++# CONFIG_WLAN_80211 is not set
++# CONFIG_IWLWIFI_LEDS is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++
++#
++# USB Network Adapters
++#
++CONFIG_USB_CATC=m
++CONFIG_USB_KAWETH=m
++CONFIG_USB_PEGASUS=m
++CONFIG_USB_RTL8150=m
++CONFIG_USB_USBNET=m
++CONFIG_USB_NET_AX8817X=m
++CONFIG_USB_NET_CDCETHER=m
++CONFIG_USB_NET_DM9601=m
++CONFIG_USB_NET_SMSC95XX=m
++CONFIG_USB_NET_GL620A=m
++CONFIG_USB_NET_NET1080=m
++CONFIG_USB_NET_PLUSB=m
++CONFIG_USB_NET_MCS7830=m
++CONFIG_USB_NET_RNDIS_HOST=m
++CONFIG_USB_NET_CDC_SUBSET=m
++# CONFIG_USB_ALI_M5632 is not set
++# CONFIG_USB_AN2720 is not set
++# CONFIG_USB_BELKIN is not set
++# CONFIG_USB_ARMLINUX is not set
++# CONFIG_USB_EPSON2888 is not set
++# CONFIG_USB_KC2190 is not set
++CONFIG_USB_NET_ZAURUS=m
++CONFIG_USB_HSO=m
++# CONFIG_WAN is not set
++# CONFIG_ATM_DRIVERS is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PPP is not set
++CONFIG_SLIP=m
++# CONFIG_SLIP_COMPRESSED is not set
++# CONFIG_SLIP_SMART is not set
++# CONFIG_SLIP_MODE_SLIP6 is not set
++# CONFIG_NET_FC is not set
++CONFIG_NETCONSOLE=m
++# CONFIG_NETCONSOLE_DYNAMIC is not set
++CONFIG_NETPOLL=y
++# CONFIG_NETPOLL_TRAP is not set
++CONFIG_NET_POLL_CONTROLLER=y
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_FF_MEMLESS=y
++CONFIG_INPUT_POLLDEV=m
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++CONFIG_INPUT_JOYDEV=y
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=m
++CONFIG_SERIO_I8042=m
++CONFIG_SERIO_SERPORT=m
++# CONFIG_SERIO_PCIPS2 is not set
++CONFIG_SERIO_RAW=m
++# CONFIG_SERIO_XILINX_XPS_PS2 is not set
++CONFIG_GAMEPORT=m
++CONFIG_GAMEPORT_NS558=m
++CONFIG_GAMEPORT_L4=m
++CONFIG_GAMEPORT_EMU10K1=m
++CONFIG_GAMEPORT_FM801=m
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_DEVKMEM=y
++# CONFIG_SERIAL_NONSTANDARD is not set
++CONFIG_NOZOMI=m
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_UARTLITE is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_SERIAL_MPC52xx=y
++CONFIG_SERIAL_MPC52xx_CONSOLE=y
++CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200
++CONFIG_SERIAL_JSM=m
++CONFIG_UNIX98_PTYS=y
++CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=256
++# CONFIG_BRIQ_PANEL is not set
++# CONFIG_HVC_RTAS is not set
++# CONFIG_HVC_UDBG is not set
++CONFIG_IPMI_HANDLER=m
++# CONFIG_IPMI_PANIC_EVENT is not set
++CONFIG_IPMI_DEVICE_INTERFACE=m
++CONFIG_IPMI_SI=m
++CONFIG_IPMI_WATCHDOG=m
++CONFIG_IPMI_POWEROFF=m
++CONFIG_HW_RANDOM=m
++CONFIG_NVRAM=y
++# CONFIG_R3964 is not set
++CONFIG_APPLICOM=m
++# CONFIG_RAW_DRIVER is not set
++CONFIG_TCG_TPM=m
++CONFIG_TCG_NSC=m
++CONFIG_TCG_ATMEL=m
++CONFIG_DEVPORT=y
++CONFIG_I2C=m
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=m
++CONFIG_I2C_HELPER_AUTO=y
++CONFIG_I2C_ALGOBIT=m
++CONFIG_I2C_ALGOPCA=m
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# PC SMBus host controller drivers
++#
++# CONFIG_I2C_ALI1535 is not set
++# CONFIG_I2C_ALI1563 is not set
++# CONFIG_I2C_ALI15X3 is not set
++# CONFIG_I2C_AMD756 is not set
++# CONFIG_I2C_AMD8111 is not set
++# CONFIG_I2C_I801 is not set
++CONFIG_I2C_ISCH=m
++# CONFIG_I2C_PIIX4 is not set
++# CONFIG_I2C_NFORCE2 is not set
++CONFIG_I2C_SIS5595=m
++CONFIG_I2C_SIS630=m
++CONFIG_I2C_SIS96X=m
++CONFIG_I2C_VIA=m
++CONFIG_I2C_VIAPRO=m
++
++#
++# Mac SMBus host controller drivers
++#
++CONFIG_I2C_HYDRA=m
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++CONFIG_I2C_MPC=m
++CONFIG_I2C_OCORES=m
++CONFIG_I2C_SIMTEC=m
++
++#
++# External I2C/SMBus adapter drivers
++#
++CONFIG_I2C_PARPORT_LIGHT=m
++CONFIG_I2C_TAOS_EVM=m
++CONFIG_I2C_TINY_USB=m
++
++#
++# Graphics adapter I2C/DDC channel drivers
++#
++CONFIG_I2C_VOODOO3=m
++
++#
++# Other I2C/SMBus bus drivers
++#
++CONFIG_I2C_PCA_PLATFORM=m
++# CONFIG_I2C_STUB is not set
++
++#
++# Miscellaneous I2C Chip support
++#
++CONFIG_DS1682=m
++CONFIG_SENSORS_PCF8574=m
++CONFIG_PCF8575=m
++CONFIG_SENSORS_PCA9539=m
++CONFIG_SENSORS_PCF8591=m
++CONFIG_SENSORS_MAX6875=m
++CONFIG_SENSORS_TSL2550=m
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_I2C_DEBUG_CHIP is not set
++# CONFIG_SPI is not set
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++# CONFIG_GPIOLIB is not set
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++CONFIG_POWER_SUPPLY_DEBUG=y
++# CONFIG_PDA_POWER is not set
++# CONFIG_WM8350_POWER is not set
++# CONFIG_BATTERY_DS2760 is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_CHARGER_PCF50633 is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_THERMAL_HWMON is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++CONFIG_SSB=m
++CONFIG_SSB_SPROM=y
++CONFIG_SSB_PCIHOST_POSSIBLE=y
++CONFIG_SSB_PCIHOST=y
++# CONFIG_SSB_B43_PCI_BRIDGE is not set
++# CONFIG_SSB_DEBUG is not set
++CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
++CONFIG_SSB_DRIVER_PCICORE=y
++
++#
++# Multifunction device drivers
++#
++CONFIG_MFD_CORE=m
++CONFIG_MFD_SM501=m
++CONFIG_HTC_PASIC3=m
++# CONFIG_MFD_TMIO is not set
++CONFIG_MFD_WM8400=m
++CONFIG_MFD_WM8350=m
++CONFIG_MFD_WM8350_I2C=m
++CONFIG_MFD_PCF50633=m
++CONFIG_PCF50633_ADC=m
++CONFIG_PCF50633_GPIO=m
++# CONFIG_REGULATOR is not set
++
++#
++# Multimedia devices
++#
++
++#
++# Multimedia core support
++#
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2_COMMON=m
++# CONFIG_VIDEO_ALLOW_V4L1 is not set
++# CONFIG_VIDEO_V4L1_COMPAT is not set
++CONFIG_DVB_CORE=m
++CONFIG_VIDEO_MEDIA=m
++
++#
++# Multimedia drivers
++#
++# CONFIG_MEDIA_ATTACH is not set
++CONFIG_MEDIA_TUNER=m
++# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set
++CONFIG_MEDIA_TUNER_SIMPLE=m
++CONFIG_MEDIA_TUNER_TDA8290=m
++CONFIG_MEDIA_TUNER_TDA9887=m
++CONFIG_MEDIA_TUNER_TEA5761=m
++CONFIG_MEDIA_TUNER_TEA5767=m
++CONFIG_MEDIA_TUNER_MT20XX=m
++CONFIG_MEDIA_TUNER_XC2028=m
++CONFIG_MEDIA_TUNER_XC5000=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
++# CONFIG_RADIO_ADAPTERS is not set
++# CONFIG_DVB_DYNAMIC_MINORS is not set
++# CONFIG_DVB_CAPTURE_DRIVERS is not set
++# CONFIG_DAB is not set
++
++#
++# Graphics support
++#
++CONFIG_AGP=m
++CONFIG_DRM=m
++CONFIG_DRM_TDFX=m
++CONFIG_DRM_R128=m
++CONFIG_DRM_RADEON=m
++CONFIG_DRM_MGA=m
++# CONFIG_DRM_SIS is not set
++CONFIG_DRM_VIA=m
++CONFIG_DRM_SAVAGE=m
++CONFIG_VGASTATE=m
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++CONFIG_FB_SYS_FILLRECT=m
++CONFIG_FB_SYS_COPYAREA=m
++CONFIG_FB_SYS_IMAGEBLIT=m
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++CONFIG_FB_SYS_FOPS=m
++CONFIG_FB_DEFERRED_IO=y
++CONFIG_FB_SVGALIB=m
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++CONFIG_FB_CIRRUS=m
++# CONFIG_FB_PM2 is not set
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_OF is not set
++# CONFIG_FB_CT65550 is not set
++# CONFIG_FB_ASILIANT is not set
++# CONFIG_FB_IMSTT is not set
++# CONFIG_FB_VGA16 is not set
++# CONFIG_FB_UVESA is not set
++CONFIG_FB_S1D13XXX=m
++# CONFIG_FB_NVIDIA is not set
++# CONFIG_FB_RIVA is not set
++# CONFIG_FB_MATROX is not set
++# CONFIG_FB_RADEON is not set
++# CONFIG_FB_ATY128 is not set
++# CONFIG_FB_ATY is not set
++CONFIG_FB_S3=m
++CONFIG_FB_SAVAGE=m
++# CONFIG_FB_SAVAGE_I2C is not set
++# CONFIG_FB_SAVAGE_ACCEL is not set
++# CONFIG_FB_SIS is not set
++CONFIG_FB_VIA=m
++CONFIG_FB_NEOMAGIC=m
++CONFIG_FB_KYRO=m
++# CONFIG_FB_3DFX is not set
++# CONFIG_FB_VOODOO1 is not set
++CONFIG_FB_VT8623=m
++CONFIG_FB_TRIDENT=m
++# CONFIG_FB_TRIDENT_ACCEL is not set
++CONFIG_FB_ARK=m
++CONFIG_FB_PM3=m
++# CONFIG_FB_CARMINE is not set
++CONFIG_FB_FSL_DIU=y
++CONFIG_FSL_DIU_FLIP_ON_VSYNC=y
++# CONFIG_FB_TMIO is not set
++CONFIG_FB_SM501=m
++CONFIG_FB_IBM_GXT4500=m
++# CONFIG_FB_VIRTUAL is not set
++CONFIG_FB_METRONOME=m
++CONFIG_FB_MB862XX=m
++# CONFIG_FB_MB862XX_PCI_GDC is not set
++# CONFIG_FB_MB862XX_LIME is not set
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++# CONFIG_LCD_CLASS_DEVICE is not set
++CONFIG_BACKLIGHT_CLASS_DEVICE=y
++# CONFIG_BACKLIGHT_GENERIC is not set
++
++#
++# Display device support
++#
++CONFIG_DISPLAY_SUPPORT=m
++
++#
++# Display hardware drivers
++#
++
++#
++# Console display driver support
++#
++CONFIG_VGA_CONSOLE=y
++# CONFIG_VGACON_SOFT_SCROLLBACK is not set
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
++CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
++# CONFIG_FONTS is not set
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++CONFIG_SOUND=y
++CONFIG_SOUND_OSS_CORE=y
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++CONFIG_SND_SEQUENCER=y
++# CONFIG_SND_SEQ_DUMMY is not set
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=m
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++CONFIG_SND_SEQUENCER_OSS=y
++# CONFIG_SND_HRTIMER is not set
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++CONFIG_SND_VERBOSE_PRINTK=y
++CONFIG_SND_DEBUG=y
++CONFIG_SND_DEBUG_VERBOSE=y
++CONFIG_SND_PCM_XRUN_DEBUG=y
++CONFIG_SND_VMASTER=y
++CONFIG_SND_AC97_CODEC=y
++CONFIG_SND_DRIVERS=y
++# CONFIG_SND_DUMMY is not set
++# CONFIG_SND_VIRMIDI is not set
++# CONFIG_SND_MTPAV is not set
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
++# CONFIG_SND_AC97_POWER_SAVE is not set
++# CONFIG_SND_PCI is not set
++# CONFIG_SND_PPC is not set
++# CONFIG_SND_USB is not set
++CONFIG_SND_SOC=y
++
++#
++# ALSA SoC audio for Freescale SOCs
++#
++CONFIG_SND_SOC_MPC5121=y
++CONFIG_SND_SOC_MPC5121_ADS=y
++# CONFIG_SND_SOC_MPC5121_I2S is not set
++CONFIG_SND_SOC_I2C_AND_SPI=m
++# CONFIG_SND_SOC_ALL_CODECS is not set
++CONFIG_SND_SOC_AC97_CODEC=y
++# CONFIG_SOUND_PRIME is not set
++CONFIG_AC97_BUS=y
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HID_DEBUG is not set
++CONFIG_HIDRAW=y
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++CONFIG_HID_PID=y
++CONFIG_USB_HIDDEV=y
++
++#
++# Special HID drivers
++#
++CONFIG_HID_COMPAT=y
++CONFIG_HID_A4TECH=y
++CONFIG_HID_APPLE=y
++CONFIG_HID_BELKIN=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++CONFIG_HID_EZKEY=y
++CONFIG_HID_GYRATION=y
++CONFIG_HID_LOGITECH=y
++CONFIG_LOGITECH_FF=y
++CONFIG_LOGIRUMBLEPAD2_FF=y
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++CONFIG_HID_NTRIG=y
++CONFIG_HID_PANTHERLORD=y
++CONFIG_PANTHERLORD_FF=y
++CONFIG_HID_PETALYNX=y
++CONFIG_HID_SAMSUNG=y
++CONFIG_HID_SONY=y
++CONFIG_HID_SUNPLUS=y
++CONFIG_GREENASIA_FF=m
++CONFIG_HID_TOPSEED=y
++CONFIG_THRUSTMASTER_FF=m
++CONFIG_ZEROPLUS_FF=m
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++CONFIG_USB_DEVICE_CLASS=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_SUSPEND is not set
++# CONFIG_USB_OTG is not set
++# CONFIG_USB_MON is not set
++CONFIG_USB_WUSB=m
++CONFIG_USB_WUSB_CBAF=m
++# CONFIG_USB_WUSB_CBAF_DEBUG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_EHCI_ROOT_HUB_TT=y
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
++CONFIG_USB_EHCI_BIG_ENDIAN_DESC=y
++CONFIG_USB_EHCI_FSL=y
++CONFIG_USB_EHCI_HCD_PPC_OF=y
++# CONFIG_USB_OXU210HP_HCD is not set
++CONFIG_USB_ISP116X_HCD=m
++# CONFIG_USB_ISP1760_HCD is not set
++CONFIG_USB_OHCI_HCD=m
++# CONFIG_USB_OHCI_HCD_PPC_OF is not set
++# CONFIG_USB_OHCI_HCD_SSB is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_UHCI_HCD=m
++CONFIG_USB_U132_HCD=m
++CONFIG_USB_SL811_HCD=m
++CONFIG_USB_R8A66597_HCD=m
++CONFIG_USB_WHCI_HCD=m
++CONFIG_USB_HWA_HCD=m
++# CONFIG_USB_MUSB_HDRC is not set
++
++#
++# USB Device Class drivers
++#
++CONFIG_USB_ACM=m
++CONFIG_USB_PRINTER=m
++CONFIG_USB_WDM=m
++CONFIG_USB_TMC=m
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
++#
++
++#
++# see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=y
++# 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_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++CONFIG_USB_LIBUSUAL=y
++
++#
++# USB Imaging devices
++#
++CONFIG_USB_MDC800=m
++CONFIG_USB_MICROTEK=m
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=m
++CONFIG_USB_EZUSB=y
++CONFIG_USB_SERIAL_GENERIC=y
++CONFIG_USB_SERIAL_AIRCABLE=m
++CONFIG_USB_SERIAL_ARK3116=m
++CONFIG_USB_SERIAL_BELKIN=m
++CONFIG_USB_SERIAL_CH341=m
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
++# CONFIG_USB_SERIAL_CP2101 is not set
++CONFIG_USB_SERIAL_CYPRESS_M8=m
++CONFIG_USB_SERIAL_EMPEG=m
++CONFIG_USB_SERIAL_FTDI_SIO=m
++CONFIG_USB_SERIAL_FUNSOFT=m
++CONFIG_USB_SERIAL_VISOR=m
++CONFIG_USB_SERIAL_IPAQ=m
++CONFIG_USB_SERIAL_IR=m
++CONFIG_USB_SERIAL_EDGEPORT=m
++CONFIG_USB_SERIAL_EDGEPORT_TI=m
++CONFIG_USB_SERIAL_GARMIN=m
++CONFIG_USB_SERIAL_IPW=m
++CONFIG_USB_SERIAL_IUU=m
++CONFIG_USB_SERIAL_KEYSPAN_PDA=m
++CONFIG_USB_SERIAL_KEYSPAN=m
++# CONFIG_USB_SERIAL_KEYSPAN_MPR 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_USA19QW is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
++CONFIG_USB_SERIAL_KLSI=m
++CONFIG_USB_SERIAL_KOBIL_SCT=m
++CONFIG_USB_SERIAL_MCT_U232=m
++CONFIG_USB_SERIAL_MOS7720=m
++CONFIG_USB_SERIAL_MOS7840=m
++CONFIG_USB_SERIAL_MOTOROLA=m
++CONFIG_USB_SERIAL_NAVMAN=m
++CONFIG_USB_SERIAL_PL2303=m
++CONFIG_USB_SERIAL_OTI6858=m
++CONFIG_USB_SERIAL_SPCP8X5=m
++CONFIG_USB_SERIAL_HP4X=m
++CONFIG_USB_SERIAL_SAFE=m
++# CONFIG_USB_SERIAL_SAFE_PADDED is not set
++CONFIG_USB_SERIAL_SIEMENS_MPI=m
++CONFIG_USB_SERIAL_SIERRAWIRELESS=m
++# CONFIG_USB_SERIAL_TI is not set
++CONFIG_USB_SERIAL_CYBERJACK=m
++CONFIG_USB_SERIAL_XIRCOM=m
++CONFIG_USB_SERIAL_OPTION=m
++CONFIG_USB_SERIAL_OMNINET=m
++CONFIG_USB_SERIAL_OPTICON=m
++CONFIG_USB_SERIAL_DEBUG=m
++
++#
++# USB Miscellaneous drivers
++#
++CONFIG_USB_EMI62=m
++CONFIG_USB_EMI26=m
++CONFIG_USB_ADUTUX=m
++CONFIG_USB_SEVSEG=m
++CONFIG_USB_RIO500=m
++CONFIG_USB_LEGOTOWER=m
++CONFIG_USB_LCD=m
++CONFIG_USB_BERRY_CHARGE=m
++CONFIG_USB_LED=m
++CONFIG_USB_CYPRESS_CY7C63=m
++CONFIG_USB_CYTHERM=m
++# CONFIG_USB_PHIDGET is not set
++CONFIG_USB_IDMOUSE=m
++CONFIG_USB_FTDI_ELAN=m
++CONFIG_USB_APPLEDISPLAY=m
++# CONFIG_USB_SISUSBVGA is not set
++CONFIG_USB_LD=m
++CONFIG_USB_TRANCEVIBRATOR=m
++CONFIG_USB_IOWARRIOR=m
++CONFIG_USB_TEST=m
++CONFIG_USB_ISIGHTFW=m
++CONFIG_USB_VST=m
++CONFIG_USB_ATM=m
++CONFIG_USB_SPEEDTOUCH=m
++CONFIG_USB_CXACRU=m
++CONFIG_USB_UEAGLEATM=m
++CONFIG_USB_XUSBATM=m
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++CONFIG_UWB=m
++CONFIG_UWB_HWA=m
++CONFIG_UWB_WHCI=m
++CONFIG_UWB_WLP=m
++CONFIG_UWB_I1480U=m
++CONFIG_UWB_I1480U_WLP=m
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++CONFIG_MMC_UNSAFE_RESUME=y
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_BOUNCE=y
++CONFIG_SDIO_UART=m
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++CONFIG_MMC_SDHCI=m
++CONFIG_MMC_SDHCI_PCI=m
++CONFIG_MMC_RICOH_MMC=m
++CONFIG_MMC_MPC5121=y
++# CONFIG_MMC_MPC5121_USE_DMA is not set
++# CONFIG_MMC_MPC5121_USE_CARD_INSERTION_INT is not set
++CONFIG_MMC_WBSD=m
++CONFIG_MMC_TIFM_SD=m
++CONFIG_MEMSTICK=m
++# CONFIG_MEMSTICK_DEBUG is not set
++
++#
++# MemoryStick drivers
++#
++# CONFIG_MEMSTICK_UNSAFE_RESUME is not set
++CONFIG_MSPRO_BLOCK=m
++
++#
++# MemoryStick Host Controller Drivers
++#
++CONFIG_MEMSTICK_TIFM_MS=m
++CONFIG_MEMSTICK_JMICRON_38X=m
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_INFINIBAND=m
++CONFIG_INFINIBAND_USER_MAD=m
++CONFIG_INFINIBAND_USER_ACCESS=m
++CONFIG_INFINIBAND_USER_MEM=y
++CONFIG_INFINIBAND_ADDR_TRANS=y
++CONFIG_INFINIBAND_MTHCA=m
++CONFIG_INFINIBAND_MTHCA_DEBUG=y
++CONFIG_INFINIBAND_AMSO1100=m
++# CONFIG_INFINIBAND_AMSO1100_DEBUG is not set
++CONFIG_MLX4_INFINIBAND=m
++CONFIG_INFINIBAND_NES=m
++# CONFIG_INFINIBAND_NES_DEBUG is not set
++CONFIG_INFINIBAND_IPOIB=m
++# CONFIG_INFINIBAND_IPOIB_CM is not set
++CONFIG_INFINIBAND_IPOIB_DEBUG=y
++# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set
++CONFIG_INFINIBAND_SRP=m
++CONFIG_INFINIBAND_ISER=m
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# I2C RTC drivers
++#
++# CONFIG_RTC_DRV_DS2068A is not set
++# CONFIG_RTC_DRV_DS1307 is not set
++# CONFIG_RTC_DRV_DS1374 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 is not set
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_PCF8563 is not set
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++
++#
++# SPI RTC drivers
++#
++
++#
++# Platform RTC drivers
++#
++# CONFIG_RTC_DRV_CMOS is not set
++# CONFIG_RTC_DRV_DS1286 is not set
++# CONFIG_RTC_DRV_DS1511 is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T35 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_BQ4802 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++# CONFIG_RTC_DRV_WM8350 is not set
++# CONFIG_RTC_DRV_PCF50633 is not set
++
++#
++# on-CPU RTC drivers
++#
++# CONFIG_RTC_DRV_PPC is not set
++CONFIG_RTC_DRV_MPC5121=y
++CONFIG_DMADEVICES=y
++
++#
++# DMA Devices
++#
++CONFIG_FSL_DMA=y
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_DMATEST is not set
++CONFIG_UIO=m
++CONFIG_UIO_CIF=m
++CONFIG_UIO_PDRV=m
++CONFIG_UIO_PDRV_GENIRQ=m
++CONFIG_UIO_SMX=m
++CONFIG_UIO_SERCOS3=m
++# CONFIG_STAGING is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++CONFIG_EXT2_FS_POSIX_ACL=y
++CONFIG_EXT2_FS_SECURITY=y
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4DEV_COMPAT=y
++CONFIG_EXT4_FS_XATTR=y
++CONFIG_EXT4_FS_POSIX_ACL=y
++CONFIG_EXT4_FS_SECURITY=y
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++CONFIG_FUSE_FS=y
++CONFIG_GENERIC_ACL=y
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=m
++CONFIG_JOLIET=y
++CONFIG_ZISOFS=y
++CONFIG_UDF_FS=m
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++CONFIG_NTFS_FS=y
++# CONFIG_NTFS_DEBUG is not set
++CONFIG_NTFS_RW=y
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_CONFIGFS_FS=m
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_YAFFS_FS=y
++CONFIG_YAFFS_YAFFS1=y
++# CONFIG_YAFFS_9BYTE_TAGS is not set
++# CONFIG_YAFFS_DOES_ECC is not set
++CONFIG_YAFFS_YAFFS2=y
++CONFIG_YAFFS_AUTO_YAFFS2=y
++CONFIG_YAFFS_DISABLE_TAGS_ECC=y
++# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
++# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
++CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED=y
++CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
++# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
++# CONFIG_JFFS2_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_SQUASHFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++CONFIG_SUNRPC_XPRT_RDMA=m
++CONFIG_SUNRPC_REGISTER_V4=y
++CONFIG_RPCSEC_GSS_KRB5=y
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++CONFIG_AMIGA_PARTITION=y
++# CONFIG_ATARI_PARTITION is not set
++CONFIG_MAC_PARTITION=y
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++CONFIG_KARMA_PARTITION=y
++# CONFIG_EFI_PARTITION is not set
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8895-i"
++CONFIG_NLS_CODEPAGE_437=y
++CONFIG_NLS_CODEPAGE_737=m
++CONFIG_NLS_CODEPAGE_775=m
++CONFIG_NLS_CODEPAGE_850=m
++CONFIG_NLS_CODEPAGE_852=m
++CONFIG_NLS_CODEPAGE_855=m
++CONFIG_NLS_CODEPAGE_857=m
++CONFIG_NLS_CODEPAGE_860=m
++CONFIG_NLS_CODEPAGE_861=m
++CONFIG_NLS_CODEPAGE_862=m
++CONFIG_NLS_CODEPAGE_863=m
++CONFIG_NLS_CODEPAGE_864=m
++CONFIG_NLS_CODEPAGE_865=m
++CONFIG_NLS_CODEPAGE_866=m
++CONFIG_NLS_CODEPAGE_869=m
++CONFIG_NLS_CODEPAGE_936=m
++CONFIG_NLS_CODEPAGE_950=m
++CONFIG_NLS_CODEPAGE_932=m
++CONFIG_NLS_CODEPAGE_949=m
++CONFIG_NLS_CODEPAGE_874=m
++CONFIG_NLS_ISO8859_8=m
++CONFIG_NLS_CODEPAGE_1250=m
++CONFIG_NLS_CODEPAGE_1251=m
++CONFIG_NLS_ASCII=m
++CONFIG_NLS_ISO8859_1=y
++CONFIG_NLS_ISO8859_2=m
++CONFIG_NLS_ISO8859_3=m
++CONFIG_NLS_ISO8859_4=m
++CONFIG_NLS_ISO8859_5=m
++CONFIG_NLS_ISO8859_6=m
++CONFIG_NLS_ISO8859_7=m
++CONFIG_NLS_ISO8859_9=m
++CONFIG_NLS_ISO8859_13=m
++CONFIG_NLS_ISO8859_14=m
++CONFIG_NLS_ISO8859_15=m
++CONFIG_NLS_KOI8_R=m
++CONFIG_NLS_KOI8_U=m
++CONFIG_NLS_UTF8=m
++# CONFIG_DLM is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_FIND_LAST_BIT=y
++CONFIG_CRC_CCITT=m
++CONFIG_CRC16=y
++CONFIG_CRC_T10DIF=y
++CONFIG_CRC_ITU_T=m
++CONFIG_CRC32=y
++CONFIG_CRC7=m
++CONFIG_LIBCRC32C=m
++CONFIG_ZLIB_INFLATE=m
++CONFIG_ZLIB_DEFLATE=m
++CONFIG_LZO_COMPRESS=m
++CONFIG_LZO_DECOMPRESS=m
++CONFIG_TEXTSEARCH=y
++CONFIG_TEXTSEARCH_KMP=m
++CONFIG_TEXTSEARCH_BM=m
++CONFIG_TEXTSEARCH_FSM=m
++CONFIG_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_HAVE_LMB=y
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_KERNEL is not set
++CONFIG_STACKTRACE=y
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_RCU_CPU_STALL_DETECTOR is not set
++# CONFIG_LATENCYTOP is not set
++# CONFIG_SYSCTL_SYSCALL_CHECK is not set
++CONFIG_NOP_TRACER=y
++CONFIG_HAVE_FUNCTION_TRACER=y
++CONFIG_HAVE_DYNAMIC_FTRACE=y
++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
++CONFIG_RING_BUFFER=y
++CONFIG_TRACING=y
++
++#
++# Tracers
++#
++# CONFIG_FIREWIRE_OHCI_REMOTE_DMA is not set
++# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++CONFIG_PRINT_STACK_DEPTH=64
++# CONFIG_IRQSTACKS is not set
++# CONFIG_VIRQ_DEBUG is not set
++# CONFIG_BOOTX_TEXT is not set
++# CONFIG_PPC_EARLY_DEBUG is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++CONFIG_SECURITYFS=y
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_FIPS=y
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD=m
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=m
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++CONFIG_CRYPTO_GF128MUL=m
++CONFIG_CRYPTO_NULL=m
++# CONFIG_CRYPTO_CRYPTD is not set
++CONFIG_CRYPTO_AUTHENC=m
++CONFIG_CRYPTO_TEST=m
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=m
++CONFIG_CRYPTO_GCM=m
++CONFIG_CRYPTO_SEQIV=m
++
++#
++# Block modes
++#
++CONFIG_CRYPTO_CBC=y
++CONFIG_CRYPTO_CTR=m
++CONFIG_CRYPTO_CTS=m
++CONFIG_CRYPTO_ECB=m
++CONFIG_CRYPTO_LRW=m
++CONFIG_CRYPTO_PCBC=m
++CONFIG_CRYPTO_XTS=m
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=m
++CONFIG_CRYPTO_XCBC=m
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=m
++CONFIG_CRYPTO_MD4=m
++CONFIG_CRYPTO_MD5=y
++CONFIG_CRYPTO_MICHAEL_MIC=m
++CONFIG_CRYPTO_RMD128=m
++CONFIG_CRYPTO_RMD160=m
++CONFIG_CRYPTO_RMD256=m
++CONFIG_CRYPTO_RMD320=m
++CONFIG_CRYPTO_SHA1=m
++CONFIG_CRYPTO_SHA256=m
++CONFIG_CRYPTO_SHA512=m
++CONFIG_CRYPTO_TGR192=m
++CONFIG_CRYPTO_WP512=m
++
++#
++# Ciphers
++#
++CONFIG_CRYPTO_AES=m
++CONFIG_CRYPTO_ANUBIS=m
++CONFIG_CRYPTO_ARC4=m
++CONFIG_CRYPTO_BLOWFISH=m
++CONFIG_CRYPTO_CAMELLIA=m
++CONFIG_CRYPTO_CAST5=m
++CONFIG_CRYPTO_CAST6=m
++CONFIG_CRYPTO_DES=y
++CONFIG_CRYPTO_FCRYPT=m
++CONFIG_CRYPTO_KHAZAD=m
++CONFIG_CRYPTO_SALSA20=m
++CONFIG_CRYPTO_SEED=m
++CONFIG_CRYPTO_SERPENT=m
++CONFIG_CRYPTO_TEA=m
++CONFIG_CRYPTO_TWOFISH=m
++CONFIG_CRYPTO_TWOFISH_COMMON=m
++
++#
++# Compression
++#
++CONFIG_CRYPTO_DEFLATE=m
++CONFIG_CRYPTO_LZO=m
++
++#
++# Random Number Generation
++#
++CONFIG_CRYPTO_ANSI_CPRNG=m
++# CONFIG_CRYPTO_HW is not set
++CONFIG_PPC_CLOCK=y
++CONFIG_PPC_LIB_RHEAP=y
++# CONFIG_VIRTUALIZATION is not set
+diff -Naur linux-2.6.29/arch/powerpc/include/asm/dma-mapping.h linux-2.6.29-v2010041601/arch/powerpc/include/asm/dma-mapping.h
+--- linux-2.6.29/arch/powerpc/include/asm/dma-mapping.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/include/asm/dma-mapping.h 2010-04-13 20:23:26.000000000 +0200
+@@ -242,19 +242,51 @@
+ static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag)
+ {
++#ifdef CONFIG_PPC64
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
++#else
++#ifdef CONFIG_NOT_COHERENT_CACHE
++ return __dma_alloc_coherent(size, dma_handle, flag);
++#else
++ void *ret;
++ /* ignore region specifiers */
++ flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
++
++ if (dev == NULL || dev->coherent_dma_mask < 0xffffffff)
++ flag |= GFP_DMA;
++
++ ret = (void *)__get_free_pages(flag, get_order(size));
++
++ if (ret != NULL) {
++ memset(ret, 0, size);
++ *dma_handle = virt_to_bus(ret);
++ }
++
++ return ret;
++#endif
++
++#endif
+ }
+
+ static inline void dma_free_coherent(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle)
+ {
++#ifdef CONFIG_PPC64
+ struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+ BUG_ON(!dma_ops);
+ dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
++#else
++#ifdef CONFIG_NOT_COHERENT_CACHE
++ __dma_free_coherent(size, cpu_addr);
++#else
++ free_pages((unsigned long)cpu_addr, get_order(size));
++#endif
++
++#endif
+ }
+
+ static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+@@ -438,6 +470,27 @@
+ BUG_ON(direction == DMA_NONE);
+ __dma_sync(vaddr, size, (int)direction);
+ }
++#ifdef CONFIG_PPC64
+
++#else
++/*
++* A helper to mmap the pages allocated via dma_alloc_coherent()
++*/
++static inline int dma_mmap_coherent(struct device *dev,
++ struct vm_area_struct *vma,
++ void *cpu_addr, dma_addr_t handle,
++ size_t size)
++{
++ struct page *pg;
++#ifdef CONFIG_NOT_COHERENT_CACHE
++ cpu_addr = bus_to_virt(handle);
++#endif
++ pg = virt_to_page(cpu_addr);
++ return remap_pfn_range(vma,
++ vma->vm_start,
++ page_to_pfn(pg) + vma->vm_pgoff,
++ size, vma->vm_page_prot);
++}
++#endif /* CONFIG_PPC64 */
+ #endif /* __KERNEL__ */
+ #endif /* _ASM_DMA_MAPPING_H */
+diff -Naur linux-2.6.29/arch/powerpc/include/asm/fsl_usb_gadget.h linux-2.6.29-v2010041601/arch/powerpc/include/asm/fsl_usb_gadget.h
+--- linux-2.6.29/arch/powerpc/include/asm/fsl_usb_gadget.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/include/asm/fsl_usb_gadget.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,25 @@
++/*
++ * Copyright (C) 2008 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Author: Bruce Schmid <duck@freescale.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++/*
++ * These routines are needed for i2c/serial transceivers
++ * on other platforms
++ */
++static inline void
++fsl_platform_set_device_mode(struct fsl_usb2_platform_data *pdata)
++{}
++
++static inline void
++fsl_platform_pullup_enable(struct fsl_usb2_platform_data *pdata)
++{}
++
++static inline void
++fsl_platform_pullup_disable(struct fsl_usb2_platform_data *pdata)
++{}
+diff -Naur linux-2.6.29/arch/powerpc/include/asm/fsl_usb.h linux-2.6.29-v2010041601/arch/powerpc/include/asm/fsl_usb.h
+--- linux-2.6.29/arch/powerpc/include/asm/fsl_usb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/include/asm/fsl_usb.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,103 @@
++/* Copyright (c) 2008 Freescale Semiconductor Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++#ifndef _FSL_USB_H
++#define _FSL_USB_H
++
++/* ehci_arc_hc_driver.flags value */
++#define FSL_PLATFORM_HC_FLAGS (HCD_USB2 | HCD_MEMORY)
++
++static void fsl_setup_phy(struct ehci_hcd *ehci, enum fsl_usb2_phy_modes phy_mode,
++ int port_offset);
++
++static inline void fsl_platform_usb_setup(struct ehci_hcd *ehci)
++{
++ struct usb_hcd *hcd = ehci_to_hcd(ehci);
++ struct fsl_usb2_platform_data *pdata;
++ void __iomem *non_ehci = hcd->regs;
++ u32 tmp;
++
++ pdata = hcd->self.controller->platform_data;
++
++ /* Enable PHY interface in the control reg. */
++ if (pdata->have_sysif_regs) {
++ out_be32(non_ehci + FSL_SOC_USB_CTRL, 0x00000004);
++ out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
++ }
++
++#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
++ /*
++ * Turn on cache snooping hardware, since some PowerPC platforms
++ * wholly rely on hardware to deal with cache coherent
++ */
++
++ /* Setup Snooping for all the 4GB space */
++ /* SNOOP1 starts from 0x0, size 2G */
++ out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0 | SNOOP_SIZE_2GB);
++ /* SNOOP2 starts from 0x80000000, size 2G */
++ out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
++#endif
++
++ if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
++ (pdata->operating_mode == FSL_USB2_DR_OTG))
++ fsl_setup_phy(ehci, pdata->phy_mode, 0);
++
++ if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
++ unsigned int chip, rev, svr;
++
++ svr = mfspr(SPRN_SVR);
++ chip = svr >> 16;
++ rev = (svr >> 4) & 0xf;
++
++ /* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */
++ if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055))
++ ehci->has_fsl_port_bug = 1;
++
++ if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
++ fsl_setup_phy(ehci, pdata->phy_mode, 0);
++ if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
++ fsl_setup_phy(ehci, pdata->phy_mode, 1);
++ }
++
++ /* put controller in host mode. */
++ tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
++ ehci_writel(ehci, tmp, non_ehci + FSL_SOC_USB_USBMODE);
++
++ if (pdata->have_sysif_regs) {
++ out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
++ out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
++ out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
++ }
++}
++
++static inline void fsl_platform_set_host_mode(struct usb_hcd *hcd)
++{
++ unsigned int temp;
++ struct fsl_usb2_platform_data *pdata;
++
++ pdata = hcd->self.controller->platform_data;
++
++ temp = in_le32(hcd->regs + FSL_SOC_USB_USBMODE);
++ temp |= USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
++ out_le32(hcd->regs + FSL_SOC_USB_USBMODE, temp);
++}
++
++/* Needed for i2c/serial transceivers */
++static inline void
++fsl_platform_set_vbus_power(struct fsl_usb2_platform_data *pdata, int on)
++{
++}
++#endif /* _FSL_USB_H */
+diff -Naur linux-2.6.29/arch/powerpc/include/asm/fsl_usb_io.h linux-2.6.29-v2010041601/arch/powerpc/include/asm/fsl_usb_io.h
+--- linux-2.6.29/arch/powerpc/include/asm/fsl_usb_io.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/include/asm/fsl_usb_io.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,107 @@
++/* Copyright (c) 2008 Freescale Semiconductor Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++#ifndef _FSL_USB_IO_H
++#define _FSL_USB_IO_H
++
++/*
++ * On some SoCs, the USB controller registers can be big or little endian,
++ * depending on the version of the chip. For these SoCs, the kernel
++ * should be configured with CONFIG_USB_FSL_BIG_ENDIAN_MMIO enabled.
++ *
++ * The "big-endian-regs" property should be specified in the USB node
++ * of the device tree for SoCs that have BE USB registers.
++ * pdata->big_endian_mmio reflects the state of that device tree property.
++ *
++ * In order to be able to run the same kernel binary on 2 different
++ * versions of an SoC, the BE/LE decision must be made at run time.
++ * _fsl_readl and fsl_writel are pointers to the BE or LE readl()
++ * and writel() functions, and fsl_readl() and fsl_writel() call through
++ * those pointers.
++ *
++ * For SoCs with the usual LE USB registers, don't enable
++ * CONFIG_USB_FSL_BIG_ENDIAN_MMIO, and then fsl_readl() and fsl_writel()
++ * are just macro wrappers for in_le32() and out_le32().
++ *
++ * In either (LE or mixed) case, the function fsl_set_usb_accessors()
++ * should be called at probe time, to either set up the readl/writel
++ * function pointers (mixed case), or do nothing (LE case).
++ *
++ * The host USB drivers already have a mechanism to handle BE/LE
++ * registers. The functionality here is intended to be used by the
++ * gadget and OTG transceiver drivers.
++ *
++ * This file also contains controller-to-cpu accessors for the
++ * USB descriptors, since their endianess is also SoC dependant.
++ * The kernel option CONFIG_USB_FSL_BIG_ENDIAN_DESC configures
++ * which way to go.
++ */
++
++#if 1 /*CONFIG_USB_FSL_BIG_ENDIAN_MMIO*/
++static u32 __maybe_unused _fsl_readl_be(const volatile void __iomem *p)
++{
++ return in_be32(p);
++}
++static u32 __maybe_unused _fsl_readl_le(const volatile void __iomem *p)
++{
++ return in_le32(p);
++}
++
++static void __maybe_unused _fsl_writel_be(u32 v, volatile void __iomem *p)
++{
++ out_be32(p, v);
++}
++static void __maybe_unused _fsl_writel_le(u32 v, volatile void __iomem *p)
++{
++ out_le32(p, v);
++}
++
++static u32 (*_fsl_readl)(const volatile void __iomem *p);
++static void (*_fsl_writel)(u32 v, volatile void __iomem *p);
++
++#define fsl_readl(p) (*_fsl_readl)((p))
++#define fsl_writel(v, p) (*_fsl_writel)((v), (p))
++
++static inline void fsl_set_usb_accessors(struct fsl_usb2_platform_data *pdata)
++{
++ if (pdata->big_endian_mmio) {
++ _fsl_readl = _fsl_readl_be;
++ _fsl_writel = _fsl_writel_be;
++ } else {
++ _fsl_readl = _fsl_readl_le;
++ _fsl_writel = _fsl_writel_le;
++ }
++}
++
++#else /* CONFIG_USB_FSL_BIG_ENDIAN_MMIO */
++
++#define fsl_readl(addr) in_le32((addr))
++#define fsl_writel(val32, addr) out_le32((addr), (val32))
++
++static inline void fsl_set_usb_accessors(struct fsl_usb2_platform_data *pdata)
++{
++}
++#endif /* CONFIG_USB_FSL_BIG_ENDIAN_MMIO */
++
++#ifdef CONFIG_USB_FSL_BIG_ENDIAN_DESC
++#define cpu_to_hc32(x) (x)
++#define hc32_to_cpu(x) (x)
++#else
++#define cpu_to_hc32(x) cpu_to_le32((x))
++#define hc32_to_cpu(x) le32_to_cpu((x))
++#endif
++
++#endif /* _FSL_USB_IO_H */
+diff -Naur linux-2.6.29/arch/powerpc/include/asm/mpc5121_struct.h linux-2.6.29-v2010041601/arch/powerpc/include/asm/mpc5121_struct.h
+--- linux-2.6.29/arch/powerpc/include/asm/mpc5121_struct.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/include/asm/mpc5121_struct.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,149 @@
++/******************
++*******************/
++#ifndef _PIEBOX_STRUCT_H_
++#define _PIEBOX_STRUCT_H_
++
++#define CFG_IMMR 0x80000000
++
++
++#define SYS_CONFIGRATION_BASE 0x0000
++#define SOFTWARE_WATCHDOG_BASE 0x0900
++#define REAL_TIME_BASE 0x0a00
++#define GENERAL_TIMER_BASE 0x0b00
++#define INTERRUPT_CONTROLER_BASE 0x0c00
++#define CSB_BASE 0x0d00
++#define RESET_BASE 0x0e00
++#define CLOCK_BASE 0x0f00
++#define POWER_MANAGEMENT_BASE 0x1000
++#define GENERAL_GPIO_BASE 0x1100
++#define MSCAN_BASE 0x1300
++#define BYTE_CONTROLLER_BASE 0x1400
++#define SECURE_DIGITAL_BASE 0x1500
++#define SONY_DIGITAL_BASE 0x1600
++#define I2C1_BASE 0x1700
++#define I2C2_BASE 0x1720
++#define I2C3_BASE 0x1740
++#define AXE_BASE 0x2000
++#define DISPLAY_BASE 0x2100
++#define CLOCK_FREQUENCY_BASE 0x2200
++#define FAST_ETHERNET_BASE 0x2800
++#define USB_ULPI_BASE 0x3000
++#define USB_UTMI_BASE 0x4000
++#define PCI_DMA_BASE 0x8000
++#define PCI_CONFIG_BASE 0x8300
++#define PCI_IOS_BASE 0x8400
++#define PCI_CONTROLLER_BASE 0x8500
++#define DRAM_CONTROLLER_BASE 0x9000
++#define IO_CONTROL_BASE 0xa000
++#define IIM_BASE 0xb000
++#define LOCALPLUS_BASE 0x10000
++#define PATA_BASE 0x10200
++#define PSC_CONTROL_BASE 0x11000
++#define PSC_N_CONTROL_BASE(n) (n*0x100+PSC_CONTROL_BASE)
++#define SFIFO_PSC_BASE 0x11f00
++#define IO_CONTROL_MEM_REG (CFG_IMMR+IO_CONTROL_BASE+0x000)
++#define IO_CONTROL_GP_REG (CFG_IMMR+IO_CONTROL_BASE+0x004)
++
++
++
++
++#define PIEBOX_LED_SET_REG(addr,value) *(volatile unsigned int *)(addr)=(value)
++
++
++#define GPIO_BIT_OFFSET(x) (1<<(31-x))
++#define GPT_BIT_OFFSET(x) (1<<(7-x))
++#define GPIO_PIEBOX_BIT_OFFSET(x) GPIO_BIT_OFFSET(x)
++
++#define GPIO_RUN_LED 1
++#define GPIO_P_LED 15
++#define GPIO_YNET_LED 14
++#define GPIO_PWROFF_MUTE 13
++
++#define COLOR_BIT_MASK (GPIO_BIT_OFFSET(GPIO_RUN_LED)|GPIO_BIT_OFFSET(GPIO_P_LED)|GPIO_BIT_OFFSET(GPIO_YNET_LED))
++/*
++#define GPIO_WIFI_P 13
++*/
++/*
++#define GPIO_PDN 12
++*/
++#define GPIO_LED_PWM 0
++#define GPIO_PENABLE_LED 11
++#define GPIO_PIEKEY_LED 10
++
++#define GPIO_KEY_VOL 20
++#define GPIO_KEY_MENU 22
++#define GPIO_KEY_LCD 3
++
++
++#define GPIO_SYSTEM_START_NORFLASH 12
++
++#define GPIO_HDR_GPIO6_LCD_ENABLE 6
++#define GPIO_LCD_GPT2 2
++
++#define LCD_BRIGHT_GPT_MAX 100
++#define LED_BRIGHT_GPT_MAX 100
++
++/**************
++gpio int mode
++******************/
++#define GPIO_INTERRUPT_MODE_ANY 0
++#define GPIO_INTERRUPT_MODE_LOW_TO_HEIGHT 1
++#define GPIO_INTERRUPT_MODE_HIGHT_TO_LOW 2
++#define GPIO_INTERRUPT_MODE_PLUSE 3
++
++
++enum{
++ PIEBOX_LED_GREEN=0,
++ PIEBOX_LED_RED,
++ PIEBOX_LED_YELLOW ,
++ PIEBOX_LED_PIEKEY
++};
++
++/************
++mtc systemcall defined
++**************/
++#define MTC_SYSTEM_CALL_NUMBER 319
++
++#define MTC_SYSTEM_CALL_SET_LCD_VALUE 0xf000
++#define MTC_SYSTEM_CALL_GET_LCD_VALUE 0xf001
++#define MTC_SYSTEM_CALL_SET_LED_VALUE 0xf002
++#define MTC_SYSTEM_CALL_GET_LED_VALUE 0xf003
++
++#define MTC_SYSTEM_CALL_GET_LED_STATUS 0xf004
++#define MTC_SYSTEM_CALL_SET_LED_STATUS 0xf005
++
++#define MTC_SYSTEM_CALL_GET_LCD_MAX 0xf006
++#define MTC_SYSTEM_CALL_GET_LED_MAX 0xf007
++
++#define MTC_SYSTEM_CALL_GET_FB0_ADDR 0xf008
++
++
++
++
++
++struct io_control_struct {
++ unsigned int io_control;
++ unsigned int value;
++};
++struct mpc5121_gpio_struct{
++ volatile unsigned int gpdir;
++ volatile unsigned int gpodr;
++ volatile unsigned int gpdat;
++ volatile unsigned int gpier;
++ volatile unsigned int gpimr;
++ volatile unsigned int gpicr1;
++ volatile unsigned int gpicr2;
++};
++struct mpc5121_gpt_struct{
++ volatile unsigned int enable_mode;
++ volatile unsigned int counter;
++ volatile unsigned int pwm_config;
++ volatile unsigned int status;
++};
++
++struct mpc5121_gpt_control_struct{
++ struct mpc5121_gpt_struct gpt[7];
++};
++ void mpc5121_usb_ide_dma_lock(void);
++ void mpc5121_usb_ide_dma_unlock(void);
++#endif
+diff -Naur linux-2.6.29/arch/powerpc/include/asm/mpc5125_nfc.h linux-2.6.29-v2010041601/arch/powerpc/include/asm/mpc5125_nfc.h
+--- linux-2.6.29/arch/powerpc/include/asm/mpc5125_nfc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/include/asm/mpc5125_nfc.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,487 @@
++/*
++ * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * Author: Shaohui Xie <b21989@freescale.com>
++ *
++ * Description:
++ * MPC5125 Nand driver.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#ifndef MPC5125_NFC_H
++#define MPC5125_NFC_H
++
++/* I/O Control Register OFFSETS */
++#define IOCTL_MEM 0x00
++#define IOCTL_GBOBE 0x01
++#define IOCTL_LPC_CLK 0x04
++#define IOCTL_LPC_OE_B 0x05
++#define IOCTL_LPC_RWB 0x06
++#define IOCTL_LPC_CS0_B 0x07
++#define IOCTL_LPC_ACK_B 0x08
++#define IOCTL_LPC_AX03 0x09
++#define IOCTL_EMB_AX02 0x0a
++#define IOCTL_EMB_AX01 0x0b
++#define IOCTL_EMB_AX00 0x0c
++#define IOCTL_EMB_AD31 0x0d
++#define IOCTL_EMB_AD30 0x0e
++#define IOCTL_EMB_AD29 0x0f
++#define IOCTL_EMB_AD28 0x10
++#define IOCTL_EMB_AD27 0x11
++#define IOCTL_EMB_AD26 0x12
++#define IOCTL_EMB_AD25 0x13
++#define IOCTL_EMB_AD24 0x14
++#define IOCTL_EMB_AD23 0x15
++#define IOCTL_EMB_AD22 0x16
++#define IOCTL_EMB_AD21 0x17
++#define IOCTL_EMB_AD20 0x18
++#define IOCTL_EMB_AD19 0x19
++#define IOCTL_EMB_AD18 0x1a
++#define IOCTL_EMB_AD17 0x1b
++#define IOCTL_EMB_AD16 0x1c
++#define IOCTL_EMB_AD15 0x1d
++#define IOCTL_EMB_AD14 0x1e
++#define IOCTL_EMB_AD13 0x1f
++#define IOCTL_EMB_AD12 0x20
++#define IOCTL_EMB_AD11 0x21
++#define IOCTL_EMB_AD10 0x22
++#define IOCTL_EMB_AD09 0x23
++#define IOCTL_EMB_AD08 0x24
++#define IOCTL_EMB_AD07 0x25
++#define IOCTL_EMB_AD06 0x26
++#define IOCTL_EMB_AD05 0x27
++#define IOCTL_EMB_AD04 0x28
++#define IOCTL_EMB_AD03 0x29
++#define IOCTL_EMB_AD02 0x2a
++#define IOCTL_EMB_AD01 0x2b
++#define IOCTL_EMB_AD00 0x2c
++#define IOCTL_NFC_CE0_B 0x2d
++#define IOCTL_NFC_RB 0x2e
++#define IOCTL_DIU_CLK 0x2f
++#define IOCTL_DIU_DE 0x30
++#define IOCTL_DIU_HSYNC 0x31
++#define IOCTL_DIU_VSYNC 0x32
++#define IOCTL_DIU_LD00 0x33
++#define IOCTL_DIU_LD01 0x34
++#define IOCTL_DIU_LD02 0x35
++#define IOCTL_DIU_LD03 0x36
++#define IOCTL_DIU_LD04 0x37
++#define IOCTL_DIU_LD05 0x38
++#define IOCTL_DIU_LD06 0x39
++#define IOCTL_DIU_LD07 0x3a
++#define IOCTL_DIU_LD08 0x3b
++#define IOCTL_DIU_LD09 0x3c
++#define IOCTL_DIU_LD10 0x3d
++#define IOCTL_DIU_LD11 0x3e
++#define IOCTL_DIU_LD12 0x3f
++#define IOCTL_DIU_LD13 0x40
++#define IOCTL_DIU_LD14 0x41
++#define IOCTL_DIU_LD15 0x42
++#define IOCTL_DIU_LD16 0x43
++#define IOCTL_DIU_LD17 0x44
++#define IOCTL_DIU_LD18 0x45
++#define IOCTL_DIU_LD19 0x46
++#define IOCTL_DIU_LD20 0x47
++#define IOCTL_DIU_LD21 0x48
++#define IOCTL_DIU_LD22 0x49
++#define IOCTL_DIU_LD23 0x4a
++#define IOCTL_I2C2_SCL 0x4b
++#define IOCTL_I2C2_SDA 0x4c
++#define IOCTL_CAN1_TX 0x4d
++#define IOCTL_CAN2_TX 0x4e
++#define IOCTL_I2C1_SCL 0x4f
++#define IOCTL_I2C1_SDA 0x50
++#define IOCTL_FEC1_TXD_2 0x51
++#define IOCTL_FEC1_TXD_3 0x52
++#define IOCTL_FEC1_RXD_2 0x53
++#define IOCTL_FEC1_RXD_3 0x54
++#define IOCTL_FEC1_CRS 0x55
++#define IOCTL_FEC1_TX_ER 0x56
++#define IOCTL_FEC1_RXD_1 0x57
++#define IOCTL_FEC1_TXD_1 0x58
++#define IOCTL_FEC1_MDC 0x59
++#define IOCTL_FEC1_RX_ER 0x5a
++#define IOCTL_FEC1_MDIO 0x5b
++#define IOCTL_FEC1_RXD_0 0x5c
++#define IOCTL_FEC1_TXD_0 0x5d
++#define IOCTL_FEC1_TX_CLK 0x5e
++#define IOCTL_FEC1_RX_CLK 0x5f
++#define IOCTL_FEC1_RX_DV 0x60
++#define IOCTL_FEC1_TX_EN 0x61
++#define IOCTL_FEC1_COL 0x62
++#define IOCTL_USB1_DATA0 0x63
++#define IOCTL_USB1_DATA1 0x64
++#define IOCTL_USB1_DATA2 0x65
++#define IOCTL_USB1_DATA3 0x66
++#define IOCTL_USB1_DATA4 0x67
++#define IOCTL_USB1_DATA5 0x68
++#define IOCTL_USB1_DATA6 0x69
++#define IOCTL_USB1_DATA7 0x6a
++#define IOCTL_USB1_STOP 0x6b
++#define IOCTL_USB1_CLK 0x6c
++#define IOCTL_USB1_NEXT 0x6d
++#define IOCTL_USB1_DIR 0x6e
++#define IOCTL_SDHC1_CLK 0x6f
++#define IOCTL_SDHC1_CMD 0x70
++#define IOCTL_SDHC1_D0 0x71
++#define IOCTL_SDHC1_D1 0x72
++#define IOCTL_SDHC1_D2 0x73
++#define IOCTL_SDHC1_D3 0x74
++#define IOCTL_PSC_MCLK_IN 0x75
++#define IOCTL_PSC0_0 0x76
++#define IOCTL_PSC0_1 0x77
++#define IOCTL_PSC0_2 0x78
++#define IOCTL_PSC0_3 0x79
++#define IOCTL_PSC0_4 0x7a
++#define IOCTL_PSC1_0 0x7b
++#define IOCTL_PSC1_1 0x7c
++#define IOCTL_PSC1_2 0x7d
++#define IOCTL_PSC1_3 0x7e
++#define IOCTL_PSC1_4 0x7f
++#define IOCTL_J1850_TX 0x80
++#define IOCTL_J1850_RX 0x81
++
++#define NFC_CE0 1
++#define NFC_CE1 2
++#define NFC_CE2 4
++#define NFC_CE3 8
++#define NFC_SEL_RB0 1
++#define NFC_SEL_RB1 2
++#define NFC_SEL_RB2 4
++#define NFC_SEL_RB3 8
++
++/******************** IO control fields ************************/
++#define DS_MSR_1 0x00
++#define DS_MSR_2 0x01
++#define DS_MSR_3 0x02
++#define DS_MSR_4 0x03
++#define ST_Disabled 0x00
++#define ST_Enabled 0x04
++#define PAD_FUNC0 0x00
++#define PAD_FUNC1 0x20
++#define PAD_FUNC2 0x40
++#define PAD_FUNC3 0x60
++#define PUD_PUE 0x18
++/**************************************************************/
++
++/* Chip select and rb select Define */
++
++/* NFC PAD Define */
++#define PAD_NFC_IO PAD_FUNC0
++#define PAD_NFC_ALE PAD_FUNC0
++#define PAD_NFC_CLE PAD_FUNC0
++#define PAD_NFC_WE PAD_FUNC0
++#define PAD_NFC_RE PAD_FUNC0
++#define PAD_NFC_CE0 PAD_FUNC0
++#define PAD_NFC_CE1 PAD_FUNC1
++#define PAD_NFC_CE2 PAD_FUNC2
++#define PAD_NFC_CE3 PAD_FUNC2
++#define PAD_NFC_RB0 PAD_FUNC0
++#define PAD_NFC_RB1 PAD_FUNC2
++#define PAD_NFC_RB2 PAD_FUNC2
++#define PAD_NFC_RB3 PAD_FUNC2
++
++/* NFC Control PAD Define */
++#define BALL_NFC_CE0 IOCTL_NFC_CE0_B
++#define BALL_NFC_CE1 IOCTL_SDHC1_CLK
++#define BALL_NFC_CE2 IOCTL_PSC1_4
++#define BALL_NFC_CE3 IOCTL_J1850_TX
++#define BALL_NFC_RB0 IOCTL_NFC_RB
++#define BALL_NFC_RB1 IOCTL_FEC1_TXD_0
++#define BALL_NFC_RB2 IOCTL_PSC1_3
++#define BALL_NFC_RB3 IOCTL_J1850_RX
++#define BALL_NFC_ALE IOCTL_EMB_AD19
++#define BALL_NFC_CLE IOCTL_EMB_AD18
++#define BALL_NFC_WE IOCTL_EMB_AD16
++#define BALL_NFC_RE IOCTL_EMB_AD17
++
++/* NFC IO Pad Define */
++#define BALL_NFC_IO0 IOCTL_EMB_AD00
++#define BALL_NFC_IO1 IOCTL_EMB_AD01
++#define BALL_NFC_IO2 IOCTL_EMB_AD02
++#define BALL_NFC_IO3 IOCTL_EMB_AD03
++#define BALL_NFC_IO4 IOCTL_EMB_AD04
++#define BALL_NFC_IO5 IOCTL_EMB_AD05
++#define BALL_NFC_IO6 IOCTL_EMB_AD06
++#define BALL_NFC_IO7 IOCTL_EMB_AD07
++
++/* Addresses for NFC MAIN RAM BUFFER areas */
++#define NFC_MAIN_AREA(n) ((n) * 0x1000)
++
++/* Addresses for NFC SPARE BUFFER areas */
++#define NFC_SPARE_BUFFERS 8
++#define NFC_SPARE_LEN 0x10
++#define NFC_SPARE_AREA(n) (0x800 + NFC_MAIN_AREA(n))
++
++#define PAGE_2K 0x0800
++#define PAGE_virtual_2K 0x0840
++#define PAGE_64 0x0040
++
++/* MPC5125 NFC registers */
++/* Typical Flash Commands */
++#define READ_PAGE_CMD_CODE 0x7EE0
++#define DMA_READ_PAGE_CMD_CODE 0x7EE0
++#define PROGRAM_PAGE_CMD_CODE 0x7FC0
++#define ERASE_CMD_CODE 0x4EC0
++#define READ_ID_CMD_CODE 0x4804
++#define RESET_CMD_CODE 0x4040
++#define DMA_PROGRAM_PAGE_CMD_CODE 0xFFC0
++#define RANDOM_IN_CMD_CODE 0x7140
++#define RANDOM_OUT_CMD_CODE 0x70E0
++#define STATUS_READ_CMD_CODE 0x4068
++
++#define PAGE_READ_CMD_BYTE1 0x00
++#define PAGE_READ_CMD_BYTE2 0x30
++#define PROGRAM_PAGE_CMD_BYTE1 0x80
++#define PROGRAM_PAGE_CMD_BYTE2 0x10
++#define READ_STATUS_CMD_BYTE 0x70
++#define ERASE_CMD_BYTE1 0x60
++#define ERASE_CMD_BYTE2 0xD0
++#define READ_ID_CMD_BYTE 0x90
++#define RESET_CMD_BYTE 0xFF
++#define RANDOM_OUT_CMD_BYTE1 0x05
++#define RANDOM_OUT_CMD_BYTE2 0xE0
++
++/* NFC ECC mode define */
++#define ECC_BYPASS 0x0
++#define ECC_8_BYTE 0x1
++#define ECC_12_BYTE 0x2
++#define ECC_15_BYTE 0x3
++#define ECC_23_BYTE 0x4
++#define ECC_30_BYTE 0x5
++#define ECC_45_BYTE 0x6
++#define ECC_60_BYTE 0x7
++#define ECC_ERROR 1
++#define ECC_RIGHT 0
++
++/***************** Module-Relative Register Offsets *************************/
++#define NFC_SRAM_BUFFER 0x0000
++#define NFC_FLASH_CMD1 0x3F00
++#define NFC_FLASH_CMD2 0x3F04
++#define NFC_COL_ADDR 0x3F08
++#define NFC_ROW_ADDR 0x3F0c
++#define NFC_FLASH_COMMAND_REPEAT 0x3F10
++#define NFC_ROW_ADDR_INC 0x3F14
++#define NFC_FLASH_STATUS1 0x3F18
++#define NFC_FLASH_STATUS2 0x3F1c
++#define NFC_DMA1_ADDR 0x3F20
++#define NFC_DMA2_ADDR 0x3F34
++#define NFC_DMA_CONFIG 0x3F24
++#define NFC_CACHE_SWAP 0x3F28
++#define NFC_SECTOR_SIZE 0x3F2c
++#define NFC_FLASH_CONFIG 0x3F30
++#define NFC_IRQ_STATUS 0x3F38
++
++/***************** Module-Relative Register Reset Value *********************/
++#define NFC_SRAM_BUFFER_RSTVAL 0x00000000
++#define NFC_FLASH_CMD1_RSTVAL 0x30FF0000
++#define NFC_FLASH_CMD2_RSTVAL 0x007EE000
++#define NFC_COL_ADDR_RSTVAL 0x00000000
++#define NFC_ROW_ADDR_RSTVAL 0x11000000
++#define NFC_FLASH_COMMAND_REPEAT_RSTVAL 0x00000000
++#define NFC_ROW_ADDR_INC_RSTVAL 0x00000001
++#define NFC_FLASH_STATUS1_RSTVAL 0x00000000
++#define NFC_FLASH_STATUS2_RSTVAL 0x00000000
++#define NFC_DMA1_ADDR_RSTVAL 0x00000000
++#define NFC_DMA2_ADDR_RSTVAL 0x00000000
++#define NFC_DMA_CONFIG_RSTVAL 0x00000000
++#define NFC_CACHE_SWAP_RSTVAL 0x0FFE0FFE
++#define NFC_SECTOR_SIZE_RSTVAL 0x00000420
++#define NFC_FLASH_CONFIG_RSTVAL 0x000EA631
++#define NFC_IRQ_STATUS_RSTVAL 0x04000000
++
++/***************** Module-Relative Register Mask *************************/
++
++/* NFC_FLASH_CMD1 Field */
++#define CMD1_MASK 0xFFFF0000
++#define CMD1_SHIFT 0
++#define CMD_BYTE2_MASK 0xFF000000
++#define CMD_BYTE2_SHIFT 24
++#define CMD_BYTE3_MASK 0x00FF0000
++#define CMD_BYTE3_SHIFT 16
++
++/* NFC_FLASH_CM2 Field */
++#define CMD2_MASK 0xFFFFFF07
++#define CMD2_SHIFT 0
++#define CMD_BYTE1_MASK 0xFF000000
++#define CMD_BYTE1_SHIFT 24
++#define CMD_CODE_MASK 0x00FFFF00
++#define CMD_CODE_SHIFT 8
++#define BUFNO_MASK 0x00000006
++#define BUFNO_SHIFT 1
++#define BUSY_MASK 0x00000001
++#define BUSY_SHIFT 0
++#define START_MASK 0x00000001
++#define START_SHIFT 0
++
++/* NFC_COL_ADDR Field */
++#define COL_ADDR_MASK 0x0000FFFF
++#define COL_ADDR_SHIFT 0
++#define COL_ADDR_COL_ADDR2_MASK 0x0000FF00
++#define COL_ADDR_COL_ADDR2_SHIFT 8
++#define COL_ADDR_COL_ADDR1_MASK 0x000000FF
++#define COL_ADDR_COL_ADDR1_SHIFT 0
++
++/* NFC_ROW_ADDR Field */
++#define ROW_ADDR_MASK 0x00FFFFFF
++#define ROW_ADDR_SHIFT 0
++#define ROW_ADDR_CHIP_SEL_RB_MASK 0xF0000000
++#define ROW_ADDR_CHIP_SEL_RB_SHIFT 28
++#define ROW_ADDR_CHIP_SEL_MASK 0x0F000000
++#define ROW_ADDR_CHIP_SEL_SHIFT 24
++#define ROW_ADDR_ROW_ADDR3_MASK 0x00FF0000
++#define ROW_ADDR_ROW_ADDR3_SHIFT 16
++#define ROW_ADDR_ROW_ADDR2_MASK 0x0000FF00
++#define ROW_ADDR_ROW_ADDR2_SHIFT 8
++#define ROW_ADDR_ROW_ADDR1_MASK 0x000000FF
++#define ROW_ADDR_ROW_ADDR1_SHIFT 0
++
++/* NFC_FLASH_COMMAND_REPEAT Field */
++#define COMMAND_REPEAT_MASK 0x0000FFFF
++#define COMMAND_REPEAT_SHIFT 0
++#define COMMAND_REPEAT_REPEAT_COUNT_MASK 0x0000FFFF
++#define COMMAND_REPEAT_REPEAT_COUNT_SHIFT 0
++
++/* NFC_ROW_ADDR_INC Field */
++#define ROW_ADDR_INC_MASK 0x00FFFFFF
++#define ROW_ADDR_INC_SHIFT 0
++#define ROW_ADDR_INC_ROW_ADDR3_INC_MASK 0x00FF0000
++#define ROW_ADDR_INC_ROW_ADDR3_INC_SHIFT 16
++#define ROW_ADDR_INC_ROW_ADDR2_INC_MASK 0x0000FF00
++#define ROW_ADDR_INC_ROW_ADDR2_INC_SHIFT 8
++#define ROW_ADDR_INC_ROW_ADDR1_INC_MASK 0x000000FF
++#define ROW_ADDR_INC_ROW_ADDR1_INC_SHIFT 0
++
++/* NFC_FLASH_STATUS1 Field */
++#define STATUS1_MASK 0xFFFFFFFF
++#define STATUS1_SHIFT 0
++#define STATUS1_ID_BYTE1_MASK 0xFF000000
++#define STATUS1_ID_BYTE1_SHIFT 24
++#define STATUS1_ID_BYTE2_MASK 0x00FF0000
++#define STATUS1_ID_BYTE2_SHIFT 16
++#define STATUS1_ID_BYTE3_MASK 0x0000FF00
++#define STATUS1_ID_BYTE3_SHIFT 8
++#define STATUS1_ID_BYTE4_MASK 0x000000FF
++#define STATUS1_ID_BYTE4_SHIFT 0
++
++/* NFC_FLASH_STATUS2 Field */
++#define STATUS2_MASK 0xFF0000FF
++#define STATUS2_SHIFT 0
++#define STATUS2_ID_BYTE5_MASK 0xFF000000
++#define STATUS2_ID_BYTE5_SHIFT 24
++#define STATUS_BYTE1_MASK 0x000000FF
++#define STATUS2_STATUS_BYTE1_SHIFT 0
++
++/* NFC_DMA1_ADDR Field */
++#define DMA1_ADDR_MASK 0xFFFFFFFF
++#define DMA1_ADDR_SHIFT 0
++#define DMA1_ADDR_DMA1_ADDR_MASK 0xFFFFFFFF
++#define DMA1_ADDR_DMA1_ADDR_SHIFT 0
++
++/* DMA2_ADDR Field */
++#define DMA2_ADDR_MASK 0xFFFFFFFF
++#define DMA2_ADDR_SHIFT 0
++#define DMA2_ADDR_DMA2_ADDR_MASK 0xFFFFFFFF
++#define DMA2_ADDR_DMA2_ADDR_SHIFT 0
++
++/* DMA_CONFIG Field */
++#define DMA_CONFIG_MASK 0xFFFFFFFF
++#define DMA_CONFIG_SHIFT 0
++#define DMA_CONFIG_DMA1_CNT_MASK 0xFFF00000
++#define DMA_CONFIG_DMA1_CNT_SHIFT 20
++#define DMA_CONFIG_DMA2_CNT_MASK 0x000FE000
++#define DMA_CONFIG_DMA2_CNT_SHIFT 13
++#define DMA_CONFIG_DMA2_OFFSET_MASK 0x00001FC0
++#define DMA_CONFIG_DMA2_OFFSET_SHIFT 2
++#define DMA_CONFIG_DMA1_ACT_MASK 0x00000002
++#define DMA_CONFIG_DMA1_ACT_SHIFT 1
++#define DMA_CONFIG_DMA2_ACT_MASK 0x00000001
++#define DMA_CONFIG_DMA2_ACT_SHIFT 0
++
++/* NFC_CACHE_SWAP Field */
++#define CACHE_SWAP_MASK 0x0FFE0FFE
++#define CACHE_SWAP_SHIFT 1
++#define CACHE_SWAP_CACHE_SWAP_ADDR2_MASK 0x0FFE0000
++#define CACHE_SWAP_CACHE_SWAP_ADDR2_SHIFT 17
++#define CACHE_SWAP_CACHE_SWAP_ADDR1_MASK 0x00000FFE
++#define CACHE_SWAP_CACHE_SWAP_ADDR1_SHIFT 1
++
++/* NFC_SECTOR_SIZE Field */
++#define SECTOR_SIZE_MASK 0x00001FFF
++#define SECTOR_SIZE_SHIFT 0
++#define SECTOR_SIZE_SECTOR_SIZE_MASK 0x00001FFF
++#define SECTOR_SIZE_SECTOR_SIZE_SHIFT 0
++
++/* NFC_FLASH_CONFIG Field */
++#define CONFIG_MASK 0xFFFFFFFF
++#define CONFIG_SHIFT 0
++#define CONFIG_STOP_ON_WERR_MASK 0x80000000
++#define CONFIG_STOP_ON_WERR_SHIFT 31
++#define CONFIG_ECC_SRAM_ADDR_MASK 0x7FC00000
++#define CONFIG_ECC_SRAM_ADDR_SHIFT 22
++#define CONFIG_ECC_SRAM_REQ_MASK 0x00200000
++#define CONFIG_ECC_SRAM_REQ_SHIFT 21
++#define CONFIG_DMA_REQ_MASK 0x00100000
++#define CONFIG_DMA_REQ_SHIFT 20
++#define CONFIG_ECC_MODE_MASK 0x000E0000
++#define CONFIG_ECC_MODE_SHIFT 17
++#define CONFIG_FAST_FLASH_MASK 0x00010000
++#define CONFIG_FAST_FLASH_SHIFT 16
++#define CONFIG_ID_COUNT_MASK 0x0000E000
++#define CONFIG_ID_COUNT_SHIFT 13
++#define CONFIG_CMD_TIMEOUT_MASK 0x00001F00
++#define CONFIG_CMD_TIMEOUT_SHIFT 8
++#define CONFIG_16BIT_MASK 0x00000080
++#define CONFIG_16BIT_SHIFT 7
++#define CONFIG_BOOT_MODE_MASK 0x00000040
++#define CONFIG_BOOT_MODE_SHIFT 6
++#define CONFIG_ADDR_AUTO_INCR_MASK 0x00000020
++#define CONFIG_ADDR_AUTO_INCR_SHIFT 5
++#define CONFIG_BUFNO_AUTO_INCR_MASK 0x00000010
++#define CONFIG_BUFNO_AUTO_INCR_SHIFT 4
++#define CONFIG_PAGE_CNT_MASK 0x0000000F
++#define CONFIG_PAGE_CNT_SHIFT 0
++
++/* NFC_IRQ_STATUS Field */
++#define MASK 0xEFFC003F
++#define SHIFT 0
++#define WERR_IRQ_MASK 0x80000000
++#define WERR_IRQ_SHIFT 31
++#define CMD_DONE_IRQ_MASK 0x40000000
++#define CMD_DONE_IRQ_SHIFT 30
++#define IDLE_IRQ_MASK 0x20000000
++#define IDLE_IRQ_SHIFT 29
++#define WERR_STATUS_MASK 0x08000000
++#define WERR_STATUS_SHIFT 27
++#define FLASH_CMD_BUSY_MASK 0x04000000
++#define FLASH_CMD_BUSY_SHIFT 26
++#define RESIDUE_BUSY_MASK 0x02000000
++#define RESIDUE_BUSY_SHIFT 25
++#define ECC_BUSY_MASK 0x01000000
++#define ECC_BUSY_SHIFT 24
++#define DMA_BUSY_MASK 0x00800000
++#define DMA_BUSY_SHIFT 23
++#define WERR_EN_MASK 0x00400000
++#define WERR_EN_SHIFT 22
++#define CMD_DONE_EN_MASK 0x00200000
++#define CMD_DONE_EN_SHIFT 21
++#define IDLE_EN_MASK 0x00100000
++#define IDLE_EN_SHIFT 20
++#define WERR_CLEAR_MASK 0x00080000
++#define WERR_CLEAR_SHIFT 19
++#define CMD_DONE_CLEAR_MASK 0x00040000
++#define CMD_DONE_CLEAR_SHIFT 18
++#define IDLE_CLEAR_MASK 0x00020000
++#define IDLE_CLEAR_SHIFT 17
++#define RESIDUE_BUFF_NO_MASK 0x00000030
++#define RESIDUE_BUFF_NO_SHIFT 4
++#define ECC_BUFF_NO_MASK 0x000000C0
++#define ECC_BUFF_NO_SHIFT 2
++#define DMA_BUFF_NO_MASK 0x00000003
++
++#endif /* MPC5125_NFC_H */
++
+diff -Naur linux-2.6.29/arch/powerpc/include/asm/mpc512x.h linux-2.6.29-v2010041601/arch/powerpc/include/asm/mpc512x.h
+--- linux-2.6.29/arch/powerpc/include/asm/mpc512x.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/include/asm/mpc512x.h 2010-04-13 20:23:26.000000000 +0200
+@@ -16,7 +16,114 @@
+ #ifndef __ASM_POWERPC_MPC512x_H__
+ #define __ASM_POWERPC_MPC512x_H__
+
++/*
++ * DDR Memory Controller Memory Map
++ */
++struct ddr512x {
++ u32 ddr_sys_config; /* System Configuration Register */
++ u32 ddr_time_config0; /* Timing Configuration Register */
++ u32 ddr_time_config1; /* Timing Configuration Register */
++ u32 ddr_time_config2; /* Timing Configuration Register */
++ u32 ddr_command; /* Command Register */
++ u32 ddr_compact_command; /* Compact Command Register */
++ u16 pad_0; /* Padding for Self Refresh Command Register 0 */
++ u16 self_refresh_cmd_0; /* Enter/Exit Self Refresh Registers */
++ u16 pad_1; /* Padding for Self Refresh Command Register 1 */
++ u16 self_refresh_cmd_1; /* Enter/Exit Self Refresh Registers */
++ u16 pad_2; /* Padding for Self Refresh Command Register 2 */
++ u16 self_refresh_cmd_2; /* Enter/Exit Self Refresh Registers */
++ u16 pad_3; /* Padding for Self Refresh Command Register 3 */
++ u16 self_refresh_cmd_3; /* Enter/Exit Self Refresh Registers */
++ u16 pad_4; /* Padding for Self Refresh Command Register 4 */
++ u16 self_refresh_cmd_4; /* Enter/Exit Self Refresh Registers */
++ u16 pad_5; /* Padding for Self Refresh Command Register 5 */
++ u16 self_refresh_cmd_5; /* Enter/Exit Self Refresh Registers */
++ u16 pad_6; /* Padding for Self Refresh Command Register 6 */
++ u16 self_refresh_cmd_6; /* Enter/Exit Self Refresh Registers */
++ u16 pad_7; /* Padding for Self Refresh Command Register 7 */
++ u16 self_refresh_cmd_7; /* Enter/Exit Self Refresh Registers */
++ u32 DQS_config_offset_count; /* DQS Config Offset Count */
++ u32 DQS_config_offset_time; /* DQS Config Offset Time */
++ u32 DQS_delay_status; /* DQS Delay Status */
++ u32 res0[0xF];
++ u32 prioman_config1; /* Priority Manager Configuration */
++ u32 prioman_config2; /* Priority Manager Configuration */
++ u32 hiprio_config; /* High Priority Configuration */
++ u32 lut_table0_main_upper; /* LUT0 Main Upper */
++ u32 lut_table1_main_upper; /* LUT1 Main Upper */
++ u32 lut_table2_main_upper; /* LUT2 Main Upper */
++ u32 lut_table3_main_upper; /* LUT3 Main Upper */
++ u32 lut_table4_main_upper; /* LUT4 Main Upper */
++ u32 lut_table0_main_lower; /* LUT0 Main Lower */
++ u32 lut_table1_main_lower; /* LUT1 Main Lower */
++ u32 lut_table2_main_lower; /* LUT2 Main Lower */
++ u32 lut_table3_main_lower; /* LUT3 Main Lower */
++ u32 lut_table4_main_lower; /* LUT4 Main Lower */
++ u32 lut_table0_alternate_upper; /* LUT0 Alternate Upper */
++ u32 lut_table1_alternate_upper; /* LUT1 Alternate Upper */
++ u32 lut_table2_alternate_upper; /* LUT2 Alternate Upper */
++ u32 lut_table3_alternate_upper; /* LUT3 Alternate Upper */
++ u32 lut_table4_alternate_upper; /* LUT4 Alternate Upper */
++ u32 lut_table0_alternate_lower; /* LUT0 Alternate Lower */
++ u32 lut_table1_alternate_lower; /* LUT1 Alternate Lower */
++ u32 lut_table2_alternate_lower; /* LUT2 Alternate Lower */
++ u32 lut_table3_alternate_lower; /* LUT3 Alternate Lower */
++ u32 lut_table4_alternate_lower; /* LUT4 Alternate Lower */
++ u32 performance_monitor_config;
++ u32 event_time_counter;
++ u32 event_time_preset;
++ u32 performance_monitor1_address_low;
++ u32 performance_monitor2_address_low;
++ u32 performance_monitor1_address_hi;
++ u32 performance_monitor2_address_hi;
++ u32 res1[2];
++ u32 performance_monitor1_read_counter;
++ u32 performance_monitor2_read_counter;
++ u32 performance_monitor1_write_counter;
++ u32 performance_monitor2_write_counter;
++ u32 granted_ack_counter0;
++ u32 granted_ack_counter1;
++ u32 granted_ack_counter2;
++ u32 granted_ack_counter3;
++ u32 granted_ack_counter4;
++ u32 cumulative_wait_counter0;
++ u32 cumulative_wait_counter1;
++ u32 cumulative_wait_counter2;
++ u32 cumulative_wait_counter3;
++ u32 cumulative_wait_counter4;
++ u32 summed_priority_counter0;
++ u32 summed_priority_counter1;
++ u32 summed_priority_counter2;
++ u32 summed_priority_counter3;
++ u32 summed_priority_counter4;
++ u32 res2[0x3AD];
++};
++
++#define MPC512x_DDR_BASE 0x9000 /* Offset of DRAM controller */
++
++struct clk;
++
+ extern unsigned long mpc512x_find_ips_freq(struct device_node *node);
++extern struct clk *clk_get(struct device *dev, const char *id);
++extern int clk_enable(struct clk *clk);
++
++
++/*
++ * helper routines for switching psc pins to gpios and back
++ * and driving them high or low
++ */
++extern void mpc5121_pscgpio_make_gpio(int psc, int pin);
++extern void mpc5121_pscgpio_pin_high(int psc, int pin);
++extern void mpc5121_pscgpio_pin_low(int psc, int pin);
++extern void mpc5121_pscgpio_make_psc(int psc, int pin);
++#ifdef CONFIG_PPC_MPC5125
++extern void mpc5125_psc_io_controller_set(int psc, int pin,unsigned char value);
++extern void mpc5125_io_controller_set(int offset,unsigned char value);
++extern void mpc5121_pscgpio_make_psc_pull_up(int psc, int pin);
++#endif
++#ifdef CONFIG_PM
++extern int __init mpc512x_pm_init(void);
++#endif
+
+ #endif /* __ASM_POWERPC_MPC512x_H__ */
+
+diff -Naur linux-2.6.29/arch/powerpc/include/asm/mpc52xx_psc.h linux-2.6.29-v2010041601/arch/powerpc/include/asm/mpc52xx_psc.h
+--- linux-2.6.29/arch/powerpc/include/asm/mpc52xx_psc.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/include/asm/mpc52xx_psc.h 2010-04-13 20:23:26.000000000 +0200
+@@ -134,6 +134,51 @@
+
+ /* Structure of the hardware registers */
+ struct mpc52xx_psc {
++#ifdef CONFIG_PPC_MPC5125
++ u8 mr1; /* PSC + 0x00 */
++ u8 reserved0[3];
++ u8 mr2; /* PSC + 0x04 */
++ u8 reserved1[3];
++ u16 mpc52xx_psc_status; /* PSC + 0x08 */
++ u8 reserved2[2];
++ u8 mpc52xx_psc_clock_select; /* PSC + 0x0c */
++ u8 reserved3[3];
++ u8 command; /* PSC + 0x10 */
++ u8 reserved4[3];
++ union { /* PSC + 0x14 */
++ u8 buffer_8;
++ u16 buffer_16;
++ u32 buffer_32;
++ } buffer;
++#define mpc52xx_psc_buffer_8 buffer.buffer_8
++#define mpc52xx_psc_buffer_16 buffer.buffer_16
++#define mpc52xx_psc_buffer_32 buffer.buffer_32
++ u8 mpc52xx_psc_ipcr; /* PSC + 0x18 */
++ u8 reserved5[3];
++ u8 mpc52xx_psc_acr; /* PSC + 0x1c */
++ u8 reserved6[3];
++ u16 mpc52xx_psc_isr; /* PSC + 0x20 */
++ u8 reserved7[2];
++ u16 mpc52xx_psc_imr; /* PSC + 0x24 */
++ u8 reserved8[2];
++ u8 ctur; /* PSC + 0x28 */
++ u8 reserved9[3];
++ u8 ctlr; /* PSC + 0x2c */
++ u8 reserved10[3];
++ u32 ccr; /* PSC + 0x30 */
++ u32 ac97slots; /* PSC + 0x34 */
++ u32 ac97cmd; /* PSC + 0x38 */
++ u32 ac97data; /* PSC + 0x3c */
++ u8 reserved11[4];
++ u8 ip; /* PSC + 0x44 */
++ u8 reserved12[3];
++ u8 op1; /* PSC + 0x48 */
++ u8 reserved13[3];
++ u8 op0; /* PSC + 0x4c */
++ u8 reserved14[3];
++ u32 sicr; /* PSC + 0x50 */
++ u8 reserved15[4];
++#else
+ u8 mode; /* PSC + 0x00 */
+ u8 reserved0[3];
+ union { /* PSC + 0x04 */
+@@ -171,12 +216,15 @@
+ u8 reserved5[3];
+ u8 ctlr; /* PSC + 0x1c */
+ u8 reserved6[3];
+- /* BitClkDiv field of CCR is byte swapped in
+- * the hardware for mpc5200/b compatibility */
+- u32 ccr; /* PSC + 0x20 */
+- u32 ac97_slots; /* PSC + 0x24 */
+- u32 ac97_cmd; /* PSC + 0x28 */
+- u32 ac97_data; /* PSC + 0x2c */
++#ifdef CONFIG_PPC_MPC5121
++ u32 ccr; /* PSC + 0x20 */
++ u32 ac97slots; /* PSC + 0x24 */
++ u32 ac97cmd; /* PSC + 0x28 */
++ u32 ac97data; /* PSC + 0x2c */
++#else
++ u16 ccr; /* PSC + 0x20 */
++ u8 reserved7[14];
++#endif
+ u8 ivr; /* PSC + 0x30 */
+ u8 reserved8[3];
+ u8 ip; /* PSC + 0x34 */
+@@ -196,6 +244,7 @@
+ u8 reserved16[3];
+ u8 irfdr; /* PSC + 0x54 */
+ u8 reserved17[3];
++#endif
+ };
+
+ struct mpc52xx_psc_fifo {
+@@ -233,16 +282,19 @@
+ u16 tflwfptr; /* PSC + 0x9e */
+ };
+
+-#define MPC512x_PSC_FIFO_RESET_SLICE 0x80
+-#define MPC512x_PSC_FIFO_ENABLE_SLICE 0x01
+-#define MPC512x_PSC_FIFO_ENABLE_DMA 0x04
++#define MPC512x_PSC_FIFO_EOF 0x100
++#define MPC512x_PSC_FIFO_RESET_SLICE 0x080
++#define MPC512x_PSC_FIFO_ENABLE_AXE 0x008
++#define MPC512x_PSC_FIFO_ENABLE_DMA 0x004
++#define MPC512x_PSC_FIFO_ENABLE_SLICE 0x001
+
+ #define MPC512x_PSC_FIFO_EMPTY 0x1
+ #define MPC512x_PSC_FIFO_FULL 0x2
+ #define MPC512x_PSC_FIFO_ALARM 0x4
+ #define MPC512x_PSC_FIFO_URERR 0x8
+-#define MPC512x_PSC_FIFO_ORERR 0x01
+-#define MPC512x_PSC_FIFO_MEMERROR 0x02
++#define MPC512x_PSC_FIFO_ORERR 0x10
++#define MPC512x_PSC_FIFO_DATARDY 0x20
++#define MPC512x_PSC_FIFO_MEMERROR 0x40
+
+ struct mpc512x_psc_fifo {
+ u32 reserved1[10];
+@@ -282,4 +334,7 @@
+ #define rxdata_32 rxdata.rxdata_32
+ };
+
++/* extract and scale size field in txsz or rxsz */
++#define MPC512x_PSC_FIFO_SZ(sz) ((sz & 0x7ff) << 2)
++
+ #endif /* __ASM_MPC52xx_PSC_H__ */
+diff -Naur linux-2.6.29/arch/powerpc/include/asm/of_platform.h linux-2.6.29-v2010041601/arch/powerpc/include/asm/of_platform.h
+--- linux-2.6.29/arch/powerpc/include/asm/of_platform.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/include/asm/of_platform.h 2010-04-13 20:23:26.000000000 +0200
+@@ -11,6 +11,9 @@
+ *
+ */
+
++/* This is just here during the transition */
++#include <linux/of_platform.h>
++
+ /* Platform drivers register/unregister */
+ static inline int of_register_platform_driver(struct of_platform_driver *drv)
+ {
+diff -Naur linux-2.6.29/arch/powerpc/include/asm/systbl.h linux-2.6.29-v2010041601/arch/powerpc/include/asm/systbl.h
+--- linux-2.6.29/arch/powerpc/include/asm/systbl.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/include/asm/systbl.h 2010-04-13 20:23:26.000000000 +0200
+@@ -322,3 +322,4 @@
+ SYSCALL_SPU(dup3)
+ SYSCALL_SPU(pipe2)
+ SYSCALL(inotify_init1)
++SYSCALL(mtc_system_call)
+\ Kein Zeilenumbruch am Dateiende.
+diff -Naur linux-2.6.29/arch/powerpc/include/asm/unistd.h linux-2.6.29-v2010041601/arch/powerpc/include/asm/unistd.h
+--- linux-2.6.29/arch/powerpc/include/asm/unistd.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/include/asm/unistd.h 2010-04-13 20:23:26.000000000 +0200
+@@ -341,10 +341,11 @@
+ #define __NR_dup3 316
+ #define __NR_pipe2 317
+ #define __NR_inotify_init1 318
++#define __NR_mtc_system_call 319
+
+ #ifdef __KERNEL__
+
+-#define __NR_syscalls 319
++#define __NR_syscalls 320
+
+ #define __NR__exit __NR_exit
+ #define NR_syscalls __NR_syscalls
+diff -Naur linux-2.6.29/arch/powerpc/Kconfig linux-2.6.29-v2010041601/arch/powerpc/Kconfig
+--- linux-2.6.29/arch/powerpc/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -199,14 +199,6 @@
+ depends on BROKEN || (PPC_PMAC64 && EXPERIMENTAL)
+ default y
+
+-config ARCH_HIBERNATION_POSSIBLE
+- bool
+- depends on (PPC64 && HIBERNATE_64) || (PPC32 && HIBERNATE_32)
+- default y
+-
+-config ARCH_SUSPEND_POSSIBLE
+- def_bool y
+- depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx
+
+ config PPC_DCR_NATIVE
+ bool
+@@ -234,12 +226,22 @@
+ source "arch/powerpc/sysdev/Kconfig"
+ source "arch/powerpc/platforms/Kconfig"
+
++
++
+ menu "Kernel options"
+
+ config HIGHMEM
+ bool "High memory support"
+ depends on PPC32
++config ARCH_HIBERNATION_POSSIBLE
++ bool "hibernation possible"
++ depends on (PPC64 && HIBERNATE_64) || (PPC32 && HIBERNATE_32) || PPC32
++ default y
+
++config ARCH_SUSPEND_POSSIBLE
++ bool "arch suspend possible"
++ depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || PPC32
++ default y
+ source kernel/time/Kconfig
+ source kernel/Kconfig.hz
+ source kernel/Kconfig.preempt
+@@ -729,6 +731,28 @@
+ config LOWMEM_SIZE
+ hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL
+ default "0x30000000"
++config AXEMBX_RESERVE_BOOL
++ bool "Reserved memory for AXE and/or MBX driver"
++ depends on ADVANCED_OPTIONS
++ help
++ This option allows you to reserve a range of memory for the AXE driver
++ this is useful for guaranteeing that the AXE driver gets memory under 16M
++ and for reserving a contiguous region for MBX frame buffers
++
++ Say N here unless you know what you are doing.
++
++config AXEMBX_RESERVE_START
++ hex "Start of reserved AXE and MBX driver memory in bytes" if AXEMBX_RESERVE_BOOL
++ default "0x00400000"
++
++config AXE_RESERVE_SIZE
++ hex "Size of reserved AXE driver memory in bytes" if AXEMBX_RESERVE_BOOL
++ default "0x00100000"
++
++config MBX_RESERVE_SIZE
++ hex "Size of reserved MBX driver memory in bytes" if AXEMBX_RESERVE_BOOL
++ default "0x04000000"
++
+
+ config RELOCATABLE
+ bool "Build a relocatable kernel (EXPERIMENTAL)"
+diff -Naur linux-2.6.29/arch/powerpc/kernel/clock.c linux-2.6.29-v2010041601/arch/powerpc/kernel/clock.c
+--- linux-2.6.29/arch/powerpc/kernel/clock.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/kernel/clock.c 2010-04-13 20:23:26.000000000 +0200
+@@ -8,7 +8,7 @@
+ #include <linux/errno.h>
+ #include <linux/module.h>
+ #include <asm/clk_interface.h>
+-
++#ifndef CONFIG_MPC5125_TWR
+ struct clk_interface clk_functions;
+
+ struct clk *clk_get(struct device *dev, const char *id)
+@@ -80,3 +80,4 @@
+ return -ENOSYS;
+ }
+ EXPORT_SYMBOL(clk_set_parent);
++#endif
+diff -Naur linux-2.6.29/arch/powerpc/kernel/head_32.S linux-2.6.29-v2010041601/arch/powerpc/kernel/head_32.S
+--- linux-2.6.29/arch/powerpc/kernel/head_32.S 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/kernel/head_32.S 2010-04-13 20:23:26.000000000 +0200
+@@ -554,6 +554,11 @@
+ * r2: ptr to linux-style pte
+ * r3: scratch
+ */
++
++#ifdef CONFIG_PPC_MPC512x
++ b bugfix5121
++bugreturn5121:
++#endif
+ mfctr r0
+ /* Get PTE (linux-style) and check access */
+ mfspr r3,SPRN_DMISS
+@@ -629,6 +634,29 @@
+ * r2: ptr to linux-style pte
+ * r3: scratch
+ */
++#ifdef CONFIG_PPC_MPC512x
++/* MPC512x: workaround for errata in die M36P and earlier:
++* Implement LRW for TLB way.
++*/
++ mfspr r3,SPRN_DMISS
++ rlwinm r3,r3,19,25,29 /* Get Address bits 19:15 */
++ lis r2,lrw@ha /* Search index in lrw[] */
++ addi r2,r2,lrw@l
++ tophys(r2,r2)
++ lwzx r1,r3,r2 /* Get item from lrw[] */
++ cmpwi 0,r1,0 /* Was it way 0 last time? */
++ beq- 0,113f /* Then goto 113: */
++ mfspr r1,SPRN_SRR1
++ rlwinm r1,r1,0,15,13 /* Mask out SRR1[WAY] */
++ mtspr SPRN_SRR1,r1
++ li r0,0
++ stwx r0,r3,r2 /* Make lrw[] entry 0 */
++ b 114f
++113:
++ li r0,1
++ stwx r0,r3,r2 /* Make lrw[] entry 1 */
++114:
++#endif
+ mfctr r0
+ /* Get PTE (linux-style) and check access */
+ mfspr r3,SPRN_DMISS
+@@ -819,6 +847,33 @@
+ blr
+ #endif /* CONFIG_ALTIVEC */
+
++#ifdef CONFIG_PPC_MPC512x
++bugfix5121:
++/* MPC512x: workaround for errata in die M36P and earlier:
++* Implement LRW for TLB way.
++*/
++ mfspr r3,SPRN_DMISS
++ rlwinm r3,r3,19,25,29 /* Get Address bits 19:15 */
++ lis r2,lrw@ha /* Search index in lrw[] */
++ addi r2,r2,lrw@l
++ tophys(r2,r2)
++ lwzx r1,r3,r2 /* Get item from lrw[] */
++ cmpwi 0,r1,0 /* Was it way 0 last time? */
++ beq- 0,113f /* Then goto 113: */
++ mfspr r1,SPRN_SRR1
++ rlwinm r1,r1,0,15,13 /* Mask out SRR1[WAY] */
++ mtspr SPRN_SRR1,r1
++ li r0,0
++ stwx r0,r3,r2 /* Make lrw[] entry 0 */
++ b 114f
++113:
++ li r0,1
++ stwx r0,r3,r2 /* Make lrw[] entry 1 */
++114:
++ b bugreturn5121
++#endif
++
++
+ /*
+ * This code is jumped to from the startup code to copy
+ * the kernel image to physical address PHYSICAL_START.
+@@ -1334,6 +1389,12 @@
+ .long 0, 0, 0, 0, 0, 0, 0, 0
+ .long 0, 0, 0, 0, 0, 0, 0, 0
+
++lrw:
++ .long 0, 0, 0, 0, 0, 0, 0, 0
++ .long 0, 0, 0, 0, 0, 0, 0, 0
++ .long 0, 0, 0, 0, 0, 0, 0, 0
++ .long 0, 0, 0, 0, 0, 0, 0, 0
++
+ /* Room for two PTE pointers, usually the kernel and current user pointers
+ * to their respective root page table.
+ */
+diff -Naur linux-2.6.29/arch/powerpc/kernel/prom.c linux-2.6.29-v2010041601/arch/powerpc/kernel/prom.c
+--- linux-2.6.29/arch/powerpc/kernel/prom.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/kernel/prom.c 2010-04-13 20:23:26.000000000 +0200
+@@ -1023,6 +1023,31 @@
+ return 0;
+ }
+
++#ifdef CONFIG_AXEMBX_RESERVE_BOOL
++unsigned long axemem[2] = {
++ CONFIG_AXEMBX_RESERVE_START,
++ CONFIG_AXE_RESERVE_SIZE
++};
++
++unsigned long *get_axe_mem(void)
++{
++ return axemem;
++}
++EXPORT_SYMBOL(get_axe_mem);
++
++unsigned long mbxmem[2] = {
++ CONFIG_AXEMBX_RESERVE_START+CONFIG_AXE_RESERVE_SIZE,
++ CONFIG_MBX_RESERVE_SIZE
++};
++
++unsigned long *get_mbx_mem(void)
++{
++ return mbxmem;
++}
++EXPORT_SYMBOL(get_mbx_mem);
++#endif
++
++
+ static void __init early_reserve_mem(void)
+ {
+ u64 base, size;
+@@ -1038,6 +1063,12 @@
+ self_size = initial_boot_params->totalsize;
+ lmb_reserve(self_base, self_size);
+
++#ifdef CONFIG_AXEMBX_RESERVE_BOOL
++ lmb_reserve(CONFIG_AXEMBX_RESERVE_START,
++ CONFIG_AXE_RESERVE_SIZE +
++ CONFIG_MBX_RESERVE_SIZE);
++#endif
++
+ #ifdef CONFIG_BLK_DEV_INITRD
+ /* then reserve the initrd, if any */
+ if (initrd_start && (initrd_end > initrd_start))
+diff -Naur linux-2.6.29/arch/powerpc/kernel/setup-common.c linux-2.6.29-v2010041601/arch/powerpc/kernel/setup-common.c
+--- linux-2.6.29/arch/powerpc/kernel/setup-common.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/kernel/setup-common.c 2010-04-13 20:23:26.000000000 +0200
+@@ -105,7 +105,25 @@
+ if (ppc_md.machine_shutdown)
+ ppc_md.machine_shutdown();
+ }
+-
++struct mpc5121_reset_reg{
++ unsigned int con_low;
++ unsigned int con_hight;
++ unsigned int reserved[2];
++ unsigned int reset_stat;
++ unsigned int reset_mode;
++ unsigned int reset_protect;
++ unsigned int reset_control;
++ unsigned int reset_enable;
++};
++void machine_restart_hardware(void)
++{
++ volatile struct mpc5121_reset_reg *reset=ioremap(0x80000e00,0x100);
++
++ reset->reset_enable=0x01;
++ reset->reset_protect=0x52535445;
++ while(!(reset->reset_enable&0x01));
++ reset->reset_control=0x3;
++}
+ void machine_restart(char *cmd)
+ {
+ machine_shutdown();
+@@ -115,6 +133,9 @@
+ smp_send_stop();
+ #endif
+ printk(KERN_EMERG "System Halted, OK to turn off power\n");
++
++ machine_restart_hardware();
++ printk(KERN_EMERG "%s line:%d\n",__func__,__LINE__);
+ local_irq_disable();
+ while (1) ;
+ }
+diff -Naur linux-2.6.29/arch/powerpc/mm/pgtable_32.c linux-2.6.29-v2010041601/arch/powerpc/mm/pgtable_32.c
+--- linux-2.6.29/arch/powerpc/mm/pgtable_32.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/mm/pgtable_32.c 2010-04-13 20:23:26.000000000 +0200
+@@ -147,6 +147,8 @@
+ }
+ EXPORT_SYMBOL(ioremap_flags);
+
++#define ALLOW_RAM_REMAP_FOR_MBX
++
+ void __iomem *
+ __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
+ {
+@@ -178,6 +180,8 @@
+ if (p < 16*1024*1024)
+ p += _ISA_MEM_BASE;
+
++#ifndef ALLOW_RAM_REMAP_FOR_MBX
++
+ #ifndef CONFIG_CRASH_DUMP
+ /*
+ * Don't allow anybody to remap normal RAM that we're using.
+@@ -189,6 +193,7 @@
+ return NULL;
+ }
+ #endif
++#endif
+
+ if (size == 0)
+ return NULL;
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/ads5121_pm.c linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/ads5121_pm.c
+--- linux-2.6.29/arch/powerpc/platforms/512x/ads5121_pm.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/ads5121_pm.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,430 @@
++/*
++ * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * Description:
++ * This file implements power management for the ADS5121
++ *
++ * This file is part of the Linux kernel
++ *
++ * This is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/suspend.h>
++#include <linux/of_platform.h>
++#include <asm/time.h>
++#include <asm/mpc512x.h>
++#include <asm/ipic.h>
++#include <asm/reg.h>
++#include <sysdev/fsl_soc.h>
++#include "mpc512x_pm.h"
++
++static struct mpc512x_pm ads5121_pm_data;
++static struct ads5121_hib_regs *ads5121_save_ptr;
++
++/* Array to store the SRAM contents */
++static char saved_sram[256 * 1024];
++static u32 ads5121_targeted_state = MPC512x_PM_NONE;
++static u32 ads5121_set_rtc_alarm(void);
++#ifdef CONFIG_MPC5121_ADS_HIB
++int fsl_deep_sleep(void)
++{
++ return ads5121_targeted_state;
++}
++#endif
++/*
++ * Name : ads5121_save_regs
++ * Desc : This function is called to store the Peripheral registers
++ * which dont have drivers associated with it to store it back.
++ *
++ * Parameters : sram - Pointer of a Mapped Memory Location.
++ * Return : void
++ */
++static int ads5121_save_regs(u32 *sram)
++{
++ u32 *reg_ptr;
++ ads5121_save_ptr = kmalloc(sizeof(struct ads5121_hib_regs), GFP_KERNEL);
++
++ if (!ads5121_save_ptr)
++ return -1;
++
++ reg_ptr = (u32 *)((u32)ads5121_pm_data.mbar +
++ MPC512x_IMMRBAR_IPIC_OFFSET);
++ _memcpy_fromio(ads5121_save_ptr->ipic_regs, reg_ptr,
++ sizeof(ads5121_save_ptr->ipic_regs));
++
++ reg_ptr = (u32 *)((u32)ads5121_pm_data.mbar +
++ MPC512x_IMMRBAR_CLK_OFFSET);
++ _memcpy_fromio(ads5121_save_ptr->clk_regs, reg_ptr,
++ sizeof(ads5121_save_ptr->clk_regs));
++
++ reg_ptr = (u32 *)((u32)ads5121_pm_data.mbar +
++ MPC512x_IMMRBAR_GPT_OFFSET);
++ _memcpy_fromio(ads5121_save_ptr->gpt_regs, reg_ptr,
++ sizeof(ads5121_save_ptr->gpt_regs));
++
++ reg_ptr = (u32 *)((u32)ads5121_pm_data.mbar +
++ MPC512x_IMMRBAR_GPIO_OFFSET);
++ _memcpy_fromio(ads5121_save_ptr->gpio_regs, reg_ptr,
++ sizeof(ads5121_save_ptr->gpio_regs));
++
++ memcpy(saved_sram, sram, sizeof(saved_sram));
++ return 0;
++}
++
++/*
++ * Name : ads5121_restore_regs
++ * Desc : This function is called to restore the Peripheral registers
++ * which dont have drivers associated with it to restore it back.
++ *
++ * Parameters : sram - Pointer of a Mapped Memory Location.
++ * Return : void
++ */
++static void ads5121_restore_regs(u32 *sram)
++{
++ u32 *reg_ptr;
++
++ /* Disable here explicitly, needs not enable since the interrrups
++ * would be enabled latter on the suspend_enter function
++ * in the kernel/power/main.c
++ */
++ local_irq_disable();
++
++ memcpy(sram, saved_sram, sizeof(saved_sram));
++
++ reg_ptr = (u32 *)((u32)ads5121_pm_data.mbar +
++ MPC512x_IMMRBAR_IPIC_OFFSET);
++ _memcpy_toio(reg_ptr, ads5121_save_ptr->ipic_regs,
++ sizeof(ads5121_save_ptr->ipic_regs));
++
++ reg_ptr = (u32 *)((u32)ads5121_pm_data.mbar +
++ MPC512x_IMMRBAR_CLK_OFFSET);
++ _memcpy_toio(reg_ptr, ads5121_save_ptr->clk_regs,
++ sizeof(ads5121_save_ptr->clk_regs));
++
++ reg_ptr = (u32 *)((u32)ads5121_pm_data.mbar +
++ MPC512x_IMMRBAR_GPT_OFFSET);
++ _memcpy_toio(reg_ptr, ads5121_save_ptr->gpt_regs,
++ sizeof(ads5121_save_ptr->gpt_regs));
++
++ reg_ptr = (u32 *)((u32)ads5121_pm_data.mbar +
++ MPC512x_IMMRBAR_GPIO_OFFSET);
++ _memcpy_toio(reg_ptr, ads5121_save_ptr->gpio_regs,
++ sizeof(ads5121_save_ptr->gpio_regs));
++
++ kfree(ads5121_save_ptr);
++}
++
++/*
++ * Name : ads5121_hibernate
++ * Desc : This function is called to hibernate.
++ *
++ * Parameters : void
++ * Return : void
++ */
++/* Set the Target Time Register to a Future Value */
++static int ads5121_hibernate(void)
++{
++ void ads5121_low_power(u32 *, u32 *, u32);
++ /*
++ * 1. Save SRAM data to DDR
++ * 2. Copy code to SRAM
++ * 3. Configure RTC to hibernate with specified timeout.
++ * 3. Jump to SRAM and put DDR in self refresh.
++ */
++ u32 reg, ret;
++ u32 offset_minutes;
++
++ u32 *rtc = (u32 *)((u32)ads5121_pm_data.mbar +
++ MPC512x_IMMRBAR_RTC_OFFSET);
++ u32 *sram = (u32 *) in_be32((u32 *)((u32)ads5121_pm_data.mbar +
++ MPC512x_IMMRBAR_SRAM_OFFSET));
++
++ /* IOREMAP the SRAM address obtained from MBAR */
++ sram = ioremap((u32)sram, (256 * 1024));
++
++ if (!sram) {
++ printk(KERN_ERR "Error mapping SRAM\n");
++ return -1;
++ }
++
++ ret = ads5121_save_regs(sram);
++ if (ret < 0)
++ return -1;
++
++ /* Set the BC6 bit in the Keep Alive Register to indicate Hibernate.
++ * The Bit Value would retained across the power cycles.
++ */
++ reg = in_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2]);
++ reg |= (1 << 8);
++ out_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2], reg);
++
++
++ /* Set the DIS_HIB_MODE to 0 to enable the Hibernate mode
++ out of MPC5121e.
++ */
++ reg = in_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2]);
++ reg &= ~(1 << 7);
++ out_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2], reg);
++
++
++ /* Store the Value of the TTR Register in RTC so as to restore */
++ ads5121_pm_data.rtc_targettime = in_be32(&rtc[MPC512x_RTC_TTR >> 2]);
++
++ offset_minutes = ads5121_set_rtc_alarm();
++
++ ads5121_low_power(sram, ads5121_pm_data.mbar, offset_minutes);
++
++ /* We are out of hibernate.. Lets restart jiffies */
++ wakeup_decrementer();
++
++ out_be32(&rtc[MPC512x_RTC_TTR >> 2], ads5121_pm_data.rtc_targettime);
++
++ /* Reset the BC6 bit after coming out of Hibernate */
++ reg = in_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2]);
++ reg &= ~(1 << 8);
++ out_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2], reg);
++
++ /* Restore the Registers */
++ ads5121_restore_regs(sram);
++
++ /* IOUMAP this location only after the restore funcion. The restore
++ * function would copy data back and then only release this memory.
++ */
++ iounmap(sram);
++ return 0;
++}
++
++/*
++ * Name : ads5121_set_rtc_wakeup
++ * Desc : This function is called to enable the wakeup sources.
++ *
++ * Parameters : void
++ * Return : void
++ */
++static void ads5121_set_rtc_wakeup(struct mpc512x_pm *p_pmdata)
++{
++ u32 rtc_reg;
++ u32 *rtc;
++
++ if (!p_pmdata->mbar)
++ return;
++
++ rtc = (u32 *)((u32)p_pmdata->mbar + MPC512x_IMMRBAR_RTC_OFFSET);
++ rtc_reg = in_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2]);
++
++ /* Set the Active LVL values for the Wake-up Sources[1-5] */
++ rtc_reg |= MPC512x_RTCKAR_WKUP_SRCLVL;
++ out_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2], rtc_reg);
++
++ rtc_reg = in_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2]);
++ /* Enable the Wake-Up sources */
++ rtc_reg |= (MPC512x_RTCKAR_WKUP_SRCEN);
++ out_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2], rtc_reg);
++}
++
++static void ads5121_prepare_hibernate(struct mpc512x_pm *p_pmdata)
++{
++ /*
++ * Enable the wakeup sources
++ */
++ ads5121_set_rtc_wakeup(p_pmdata);
++}
++/*
++ * Name : ads5121_pm_valid
++ * Desc : Checks whether the PM state is valid
++ *
++ * Parameters : void
++ * Return : 1 - Valid , 0 - Invalid
++ */
++static int ads5121_pm_valid(suspend_state_t state)
++{
++ switch (state) {
++ case PM_SUSPEND_STANDBY:
++ case PM_SUSPEND_MEM:
++ return 1;
++ default:
++ return 0;
++ }
++}
++
++/*
++ * Name : ads5121_pm_settarget
++ * Desc : Set the state to which the system is to enter.
++ *
++ * Parameters : void
++ * Return : 0 - Success
++ */
++static int ads5121_pm_settarget(suspend_state_t state)
++{
++ switch (state) {
++ case PM_SUSPEND_STANDBY:
++ ads5121_targeted_state = MPC512x_PM_STANDBY;
++ break;
++ case PM_SUSPEND_MEM:
++ ads5121_targeted_state = MPC512x_PM_SUSP_MEM;
++ break;
++ default:
++ ads5121_targeted_state = MPC512x_PM_NONE;
++ }
++ return 0;
++}
++/*
++ * Name : ads5121_pm_prepare
++ * Desc : This function would map the IO regions. Also sets the DDRC and
++ * RTC regs for Deep Sleep Mode.
++ *
++ * Parameters : void
++ * Return : int
++ * ENOSYS
++ *
++ */
++static int ads5121_pm_prepare(void)
++{
++ mpc512x_pm_setup(&ads5121_pm_data);
++
++ switch (ads5121_targeted_state) {
++ case MPC512x_PM_STANDBY:
++ mpc512x_prepare_deepsleep(&ads5121_pm_data);
++ break;
++ case MPC512x_PM_SUSP_MEM:
++ ads5121_prepare_hibernate(&ads5121_pm_data);
++ break;
++ }
++ return 0;
++}
++
++/*
++ * Name : ads5121_pm_enter
++ * Desc : This function is exported to the Power Management Core. This
++ * ` function is called with the state which the system should enter.
++ *
++ * Parameters : state - PM_SUSPEND_STANDBY
++ - PM_SUSPEND_MEM
++ * Return : int
++ * -1 : FAILED
++ * 0 : SUCCESS
++ */
++static int ads5121_pm_enter(suspend_state_t state)
++{
++ if (!ads5121_pm_data.mbar) {
++ printk(KERN_ERR "Failed to enter PM mode as IO not mapped.\n");
++ return -1;
++ }
++ switch (ads5121_targeted_state) {
++
++ case MPC512x_PM_STANDBY:
++ mpc512x_enter_deepsleep(&ads5121_pm_data);
++ break;
++ case MPC512x_PM_SUSP_MEM:
++ ads5121_hibernate();
++ break;
++ default:
++ break;
++ }
++ return 0;
++}
++
++/*
++ * Name : ads5121_pm_finish
++ * Desc : This routine is called by the kernel on exit from
++ * power down modes. Restores the DDRC and RTC regs
++ * suspend to memory. Also releases allocated resources.
++ *
++ * Parameters : void
++ * Return : void
++ */
++static void ads5121_pm_finish(void)
++{
++ switch (ads5121_targeted_state) {
++
++ case MPC512x_PM_STANDBY:
++ mpc512x_finish_deepsleep(&ads5121_pm_data);
++ break;
++ case MPC512x_PM_SUSP_MEM:
++ break;
++ }
++ ads5121_targeted_state = MPC512x_PM_NONE;
++
++ mpc512x_pm_release(&ads5121_pm_data);
++}
++
++static struct platform_suspend_ops ads5121_pm_ops = {
++ .valid = ads5121_pm_valid,
++ .begin = ads5121_pm_settarget,
++ .prepare = ads5121_pm_prepare,
++ .enter = ads5121_pm_enter,
++ .finish = ads5121_pm_finish,
++};
++
++/*
++ * Name : ads5121_pm_init
++ * Desc : This function registers the platform_suspend_ops
++ * structure with the kernel.
++ *
++ * Parameters : void
++ * Return : int
++ */
++int __init ads5121_pm_init(void)
++{
++ suspend_set_ops(&ads5121_pm_ops);
++ return 0;
++}
++
++/*
++ * Name : ads5121_set_rtc_alarm
++ * Desc : This function woul dbe called from the ads5121_hibernate funct-
++ * which return the alarm offset in case it is set. If not then
++ * it would retun 0xFFFFFFFF, which would be the MAX value for TTR.
++ *
++ * Parameters :
++ * Return : u32 - Offset of Alarm Value with the Current Time.
++ */
++static u32 ads5121_set_rtc_alarm()
++{
++ u32 rtc_reg;
++ u32 *rtc;
++ u32 alm_hr, alm_min, cur_hr, cur_min;
++ u32 offset_minutes;
++
++ rtc = (u32 *)((u32)ads5121_pm_data.mbar + MPC512x_IMMRBAR_RTC_OFFSET);
++
++ rtc_reg = in_be32(&rtc[MPC512x_RTC_AIER >> 2]);
++
++ if (rtc_reg & MPC512x_RTCAIER_ALMEN_MASK) {
++ /*Alarm was set.. Let us wakeup in that time..*/
++ alm_hr = (rtc_reg >> MPC512x_RTC_HR_OFFSET)
++ & MPC512x_RTC_HR_MASK;
++ alm_min = (rtc_reg >> MPC512x_RTC_MIN_OFFSET)
++ & MPC512x_RTC_MIN_MASK;
++ rtc_reg = in_be32(&rtc[MPC512x_RTC_CTR >> 2]);
++ cur_min = (rtc_reg >> MPC512x_RTC_MIN_OFFSET)
++ & MPC512x_RTC_MIN_MASK;
++
++ if (in_be32(&rtc[MPC512x_RTC_TSR >> 2])
++ & MPC512x_RTCTSR_SLCHR_MASK) {
++ /* 12 Hour Format*/
++ cur_hr = (rtc_reg >> MPC512x_RTC_HR_OFFSET) & 0xF;
++ if (rtc_reg & MPC512x_RTC_CTR_PM)
++ cur_hr += 12;
++ } else
++ cur_hr = (rtc_reg >> MPC512x_RTC_HR_OFFSET)
++ & MPC512x_RTC_HR_MASK;
++ offset_minutes = (alm_hr * MPC512x_RTC_MINS_PER_HR + alm_min) -
++ (cur_hr * MPC512x_RTC_MINS_PER_HR + cur_min);
++
++ if (offset_minutes > 0)
++ offset_minutes = offset_minutes * MPC512x_RTC_MINS_PER_HR;
++ else
++ offset_minutes = MPC512x_RTCTTR_MAXTIMEOUT;
++ } else
++ offset_minutes = MPC512x_RTCTTR_MAXTIMEOUT;
++
++ return(offset_minutes);
++}
++
++
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/ads5121_sleep.S linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/ads5121_sleep.S
+--- linux-2.6.29/arch/powerpc/platforms/512x/ads5121_sleep.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/ads5121_sleep.S 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,378 @@
++/*
++ * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * Author: Harith George <harith.george@wipro.com>
++ *
++ * Implements the Power management code to enter Suspend to RAM.
++ *
++ * Original based on arch/powerpc/platforms/52xx/mpc52xx_sleep.S
++ *
++ * This program is free software; you can 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 <asm/reg.h>
++#include <asm/ppc_asm.h>
++#include <asm/processor.h>
++#include <asm/cache.h>
++
++/* Helpers... beware: r10 and r4 are overwritten */
++#define SAVE_SPRN(reg, addr) \
++ mfspr r10, SPRN_##reg; \
++ stw r10, ((addr)*4)(r4); \
++ sync;
++
++#define LOAD_SPRN(reg, addr) \
++ lwz r10, ((addr)*4)(r4); \
++ mtspr SPRN_##reg, r10; \
++ sync; \
++ isync;
++
++/* Helpers for saving registers */
++#define SAVE_BAT(n, addr) \
++ SAVE_SPRN(DBAT##n##L, addr); \
++ SAVE_SPRN(DBAT##n##U, addr+1); \
++ SAVE_SPRN(IBAT##n##L, addr+2); \
++ SAVE_SPRN(IBAT##n##U, addr+3);
++
++#define SAVE_SR(n, addr) \
++ mfsr r10, n; \
++ stw r10, ((addr)*4)(r4);
++
++#define SAVE_4SR(n, addr) \
++ SAVE_SR(n, addr); \
++ SAVE_SR(n+1, addr+1); \
++ SAVE_SR(n+2, addr+2); \
++ SAVE_SR(n+3, addr+3);
++
++/* Helpers for restoring registers */
++#define LOAD_BAT(n, addr) \
++ LOAD_SPRN(DBAT##n##L, addr); \
++ LOAD_SPRN(DBAT##n##U, addr+1); \
++ LOAD_SPRN(IBAT##n##L, addr+2); \
++ LOAD_SPRN(IBAT##n##U, addr+3);
++
++#define LOAD_SR(n, addr) \
++ lwz r10, ((addr)*4)(r4); \
++ mtsr n, r10;
++
++#define LOAD_4SR(n, addr) \
++ LOAD_SR(n, addr); \
++ LOAD_SR(n+1, addr+1); \
++ LOAD_SR(n+2, addr+2); \
++ LOAD_SR(n+3, addr+3);
++
++#define MPC5121_DDRC_OFFSET 0x9000
++#define MPC512x_IMMRBAR_RTC_OFFSET 0xA00
++#define MPC512x_DDRC_CMD0 0x3C00
++#define MPC512x_DDRC_CMD1 0x4420
++#define MPC512x_DDRC_CMD2 0x4210
++#define MPC512x_DDRC_CMD3 0x1410
++#define DDRC_SYSCONFIG_CMD (1 << 28)
++
++ .data
++registers:
++ .space 0x5d*4
++
++ .text
++ .globl ads5121_low_power
++ads5121_low_power:
++ /* Low-power mode with help of Power CPLD */
++ mr r7, r3 /* save SRAM va */
++ mr r8, r4 /* MBAR*/
++ mr r9, r5 /* Offset_minutes for setting the alarm */
++ mflr r0 /* store lr into r0 */
++
++ /* setup wakeup address for u-boot at physical location 0x0 */
++ lis r3, CONFIG_KERNEL_START@h
++ /* saving the contents of 0x00000000 at
++ * location 0x5c offset in registers
++ */
++ lis r4, registers@h
++ ori r4, r4, registers@l
++ lwz r5, 0x0(r3)
++ stw r5, (4*0x5c)(r4)
++
++ lis r4, ads5121_wakeup@h
++ ori r4, r4, ads5121_wakeup@l
++ sub r4, r4, r3
++ stw r4, 0(r3)
++ sync
++
++ lis r4, registers@h
++ ori r4, r4, registers@l
++
++ /* save registers to r4 [destroys r10] */
++ SAVE_SPRN(LR, 0x1c)
++ bl save_regs
++
++ /* copy code to sram */
++ mr r4, r7
++ li r3, (sram_code_end - sram_code)/4
++ /* Added to fix the crash issue while executing from SRAM */
++ addi r3, r3,0x3
++ mtctr r3
++ lis r3, sram_code@h
++ ori r3, r3, sram_code@l
++1:
++ lwz r5, 0(r3)
++ stw r5, 0(r4)
++ addi r3, r3, 4
++ addi r4, r4, 4
++ bdnz 1b
++
++ /* flush caches [destroys r3, r4] */
++ bl flush_data_cache
++
++ /* disable I and D caches */
++ mfspr r3, SPRN_HID0
++ ori r3, r3, HID0_ICE | HID0_DCE
++ xori r3, r3, HID0_ICE | HID0_DCE
++ sync; isync;
++ mtspr SPRN_HID0, r3
++ isync; isync;
++
++ /*
++ * We will load the RTC ATR value here so that
++ * we get the address in a TLB. We cannot get any
++ * ea->pa conversions after DDR is turned off.
++ */
++ ori r6, r8, MPC512x_IMMRBAR_RTC_OFFSET@l
++ lwz r5, 0x24(r6)
++
++ /* setting the alarm value */
++ lis r4, 0xFFFF
++ ori r4, r4,0xFFFF
++
++ /* check whether the TTR should be set
++ * to 0xFFFFFFFF or not */
++
++ xor r4, r4, r9
++ /* compare r4 with 0 and set the bit
++ * in the condition register 0 */
++ cmpi 0, r4,0
++ /* branch to "alarm" until the CR0 second bit is
++ * set i.e,equal to condition for the
++ * above comparison */
++ bc 0xC, 2, alarm
++
++ add r9, r5, r9
++alarm:
++ mr r5, r9
++
++ /* jump to sram */
++ mtlr r7
++ blrl
++ /* doesn't return */
++
++sram_code:
++ /* Put DDR in Self Refresh */
++ mr r3, r8
++ ori r3, r3, MPC5121_DDRC_OFFSET@l
++ lwz r4, 0(r3)
++ oris r4, r4, DDRC_SYSCONFIG_CMD@h
++ stw r4, 0(r3)
++ sync
++ li r4, MPC512x_DDRC_CMD0@l
++ stw r4, 0x14(r3)
++ sync
++ li r4, MPC512x_DDRC_CMD1@l
++ stw r4, 0x14(r3)
++ sync
++ li r4, MPC512x_DDRC_CMD2@l
++ stw r4, 0x14(r3)
++ sync
++ li r4, MPC512x_DDRC_CMD3@l
++ stw r4, 0x14(r3)
++ sync
++
++ /* Set TTR = ATR + 60 (0x3C)*/
++ stw r5, 0x20(r6)
++ sync
++
++sram_code_end:
++ b sram_code_end
++ sync
++ isync
++
++ /* Uboot jumps here on resume */
++ads5121_wakeup:
++ bl restore_regs
++
++ /* HIDs, MSR */
++ LOAD_SPRN(HID1, 0x19)
++ LOAD_SPRN(HID2, 0x1a)
++
++ /* address translation is tricky (see turn_on_mmu) */
++ mfmsr r10
++ ori r10, r10, MSR_DR | MSR_IR
++
++ mtspr SPRN_SRR1, r10
++ lis r10, mmu_on@h
++ ori r10, r10, mmu_on@l
++ mtspr SPRN_SRR0, r10
++ sync
++ rfi
++
++mmu_on:
++ /* kernel offset (r4 is still set from restore_registers) */
++ /* Though r4, will contain, just restoring incase if its
++ * corrupted
++ */
++ addis r4, r4, CONFIG_KERNEL_START@h
++
++ /* restore MSR */
++ lwz r10, (4*0x1b)(r4)
++ mtmsr r10
++ sync; isync;
++
++ /* invalidate caches */
++ mfspr r10, SPRN_HID0
++ ori r5, r10, HID0_ICFI | HID0_DCI
++ mtspr SPRN_HID0, r5 /* invalidate caches */
++ sync; isync;
++ mtspr SPRN_HID0, r10
++ sync; isync;
++
++ /* enable caches */
++ lwz r10, (4*0x18)(r4)
++ mtspr SPRN_HID0, r10 /* restore (enable caches, DPM) */
++ /* ^ this has to be after address translation set in MSR */
++ sync
++ isync
++
++ LOAD_SPRN(LR, 0x1c)
++ blr
++
++save_regs:
++ stw r0, 0(r4)
++ stw r1, 0x4(r4)
++ stw r2, 0x8(r4)
++ stmw r11, 0xc(r4) /* 0xc -> 0x5f, (0x18*4-1) */
++
++ SAVE_SPRN(HID0, 0x18)
++ SAVE_SPRN(HID1, 0x19)
++ SAVE_SPRN(HID2, 0x1a)
++ mfmsr r10
++ stw r10, (4*0x1b)(r4)
++ /*SAVE_SPRN(LR, 0x1c) have to save it before the call */
++ SAVE_SPRN(RPA, 0x1e)
++ SAVE_SPRN(SDR1, 0x1f)
++
++ /* save MMU regs */
++ SAVE_BAT(0, 0x20)
++ SAVE_BAT(1, 0x24)
++ SAVE_BAT(2, 0x28)
++ SAVE_BAT(3, 0x2c)
++ SAVE_BAT(4, 0x30)
++ SAVE_BAT(5, 0x34)
++ SAVE_BAT(6, 0x38)
++ SAVE_BAT(7, 0x3c)
++
++ SAVE_4SR(0, 0x40)
++ SAVE_4SR(4, 0x44)
++ SAVE_4SR(8, 0x48)
++ SAVE_4SR(12, 0x4c)
++
++ SAVE_SPRN(SPRG0, 0x50)
++ SAVE_SPRN(SPRG1, 0x51)
++ SAVE_SPRN(SPRG2, 0x52)
++ SAVE_SPRN(SPRG3, 0x53)
++ SAVE_SPRN(SPRG4, 0x54)
++ SAVE_SPRN(SPRG5, 0x55)
++ SAVE_SPRN(SPRG6, 0x56)
++ SAVE_SPRN(SPRG7, 0x57)
++
++ SAVE_SPRN(IABR, 0x58)
++ SAVE_SPRN(DABR, 0x59)
++ SAVE_SPRN(TBRL, 0x5a)
++ SAVE_SPRN(TBRU, 0x5b)
++
++ blr
++
++restore_regs:
++ lis r4, registers@h
++ ori r4, r4, registers@l
++
++ /* This only required in case when the register is directly accessed in Virtual Mode */
++ /* MMU is not up yet */
++ subis r4, r4, CONFIG_KERNEL_START@h
++
++ /* restoring the contents at 0x00000000 location
++ * from the 0x5c offset in registers
++ */
++ lis r5, CONFIG_KERNEL_START@h
++ subis r5, r5, CONFIG_KERNEL_START@h
++ lwz r3, (0x5c*4)(r4)
++ stw r3, 0x0(r5)
++
++ lwz r0, 0(r4)
++ lwz r1, 0x4(r4)
++ lwz r2, 0x8(r4)
++ lmw r11, 0xc(r4)
++
++ /*
++ * these are a bit tricky
++ * 0x18 - HID0
++ * 0x19 - HID1
++ * 0x1a - HID2
++ * 0x1b - MSR
++ * 0x1c - LR
++ */
++ LOAD_SPRN(RPA, 0x1e);
++ LOAD_SPRN(SDR1, 0x1f);
++
++ /* restore MMU regs */
++ LOAD_BAT(0, 0x20)
++ LOAD_BAT(1, 0x24)
++ LOAD_BAT(2, 0x28)
++ LOAD_BAT(3, 0x2c)
++ LOAD_BAT(4, 0x30)
++ LOAD_BAT(5, 0x34)
++ LOAD_BAT(6, 0x38)
++ LOAD_BAT(7, 0x3c)
++
++ LOAD_4SR(0, 0x40)
++ LOAD_4SR(4, 0x44)
++ LOAD_4SR(8, 0x48)
++ LOAD_4SR(12, 0x4c)
++
++ /* rest of regs */
++ LOAD_SPRN(SPRG0, 0x50);
++ LOAD_SPRN(SPRG1, 0x51);
++ LOAD_SPRN(SPRG2, 0x52);
++ LOAD_SPRN(SPRG3, 0x53);
++ LOAD_SPRN(SPRG4, 0x54);
++ LOAD_SPRN(SPRG5, 0x55);
++ LOAD_SPRN(SPRG6, 0x56);
++ LOAD_SPRN(SPRG7, 0x57);
++
++ LOAD_SPRN(IABR, 0x58);
++ LOAD_SPRN(DABR, 0x59);
++ LOAD_SPRN(TBWL, 0x5a); /* these two have separate R/W regs */
++ LOAD_SPRN(TBWU, 0x5b);
++
++ blr
++
++
++/* cache flushing code. copied from arch/ppc/boot/util.S */
++/*
++ * Flush data cache
++ * Do this by just reading lots of stuff into the cache.
++ * We copy twice the cache lines to make sure all cache
++ * is flushed..
++ */
++#define NUM_CACHE_LINES (128*8*2)
++
++flush_data_cache:
++ lis r3, CONFIG_KERNEL_START@h
++ ori r3, r3, CONFIG_KERNEL_START@l
++ li r4, NUM_CACHE_LINES
++ mtctr r4
++1:
++ lwz r4, 0(r3)
++ addi r3, r3, L1_CACHE_BYTES /* Next line, please */
++ bdnz 1b
++ blr
++
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/clock.c linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/clock.c
+--- linux-2.6.29/arch/powerpc/platforms/512x/clock.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/clock.c 2010-04-13 20:23:26.000000000 +0200
+@@ -30,10 +30,11 @@
+ #undef CLK_DEBUG
+
+ static int clocks_initialized;
++static int rev2_silicon;
+
+ #define CLK_HAS_RATE 0x1 /* has rate in MHz */
+ #define CLK_HAS_CTRL 0x2 /* has control reg and bit */
+-
++#define ROUND_1MHZ 1000000 /* 1MHZ */
+ struct clk {
+ struct list_head node;
+ char name[32];
+@@ -50,18 +51,18 @@
+ static LIST_HEAD(clocks);
+ static DEFINE_MUTEX(clocks_mutex);
+
+-static struct clk *mpc5121_clk_get(struct device *dev, const char *id)
++struct clk *clk_get(struct device *dev, const char *id)
+ {
+ struct clk *p, *clk = ERR_PTR(-ENOENT);
+ int dev_match = 0;
+ int id_match = 0;
+
+- if (dev == NULL || id == NULL)
++ if (dev == NULL && id == NULL) {
+ return NULL;
+-
++ }
+ mutex_lock(&clocks_mutex);
+ list_for_each_entry(p, &clocks, node) {
+- if (dev == p->dev)
++ if (dev && dev == p->dev)
+ dev_match++;
+ if (strcmp(id, p->name) == 0)
+ id_match++;
+@@ -74,6 +75,7 @@
+
+ return clk;
+ }
++EXPORT_SYMBOL(clk_get);
+
+ #ifdef CLK_DEBUG
+ static void dump_clocks(void)
+@@ -99,10 +101,11 @@
+ #endif
+
+
+-static void mpc5121_clk_put(struct clk *clk)
++void clk_put(struct clk *clk)
+ {
+ module_put(clk->owner);
+ }
++EXPORT_SYMBOL(clk_put);
+
+ #define NRPSC 12
+
+@@ -117,11 +120,13 @@
+ u32 spccr; /* SPDIF Clk Ctrl Reg */
+ u32 cccr; /* CFM Clk Ctrl Reg */
+ u32 dccr; /* DIU Clk Cnfg Reg */
++ /* rev2 only regs */
++ u32 mccr[4]; /* MSCAN Clk Ctrl Reg 1-3 */
+ };
+
+ struct mpc512x_clockctl __iomem *clockctl;
+
+-static int mpc5121_clk_enable(struct clk *clk)
++int clk_enable(struct clk *clk)
+ {
+ unsigned int mask;
+
+@@ -132,8 +137,9 @@
+ }
+ return 0;
+ }
++EXPORT_SYMBOL(clk_enable);
+
+-static void mpc5121_clk_disable(struct clk *clk)
++void clk_disable(struct clk *clk)
+ {
+ unsigned int mask;
+
+@@ -143,32 +149,46 @@
+ out_be32(&clockctl->sccr[clk->reg], mask);
+ }
+ }
++EXPORT_SYMBOL(clk_disable);
+
+-static unsigned long mpc5121_clk_get_rate(struct clk *clk)
++unsigned long clk_get_rate(struct clk *clk)
+ {
+- if (clk->flags & CLK_HAS_RATE)
++ if (clk->flags & CLK_HAS_RATE) {
+ return clk->rate;
+- else
++ } else {
+ return 0;
++ }
+ }
++EXPORT_SYMBOL(clk_get_rate);
+
+-static long mpc5121_clk_round_rate(struct clk *clk, unsigned long rate)
++long clk_round_rate(struct clk *clk, unsigned long rate)
+ {
+ return rate;
+ }
++EXPORT_SYMBOL(clk_round_rate);
+
+-static int mpc5121_clk_set_rate(struct clk *clk, unsigned long rate)
++int clk_set_rate(struct clk *clk, unsigned long rate)
+ {
+ return 0;
+ }
++EXPORT_SYMBOL(clk_set_rate);
+
+-static int clk_register(struct clk *clk)
++int clk_register(struct clk *clk)
+ {
+ mutex_lock(&clocks_mutex);
+ list_add(&clk->node, &clocks);
+ mutex_unlock(&clocks_mutex);
+ return 0;
+ }
++EXPORT_SYMBOL(clk_register);
++
++void clk_unregister(struct clk *clk)
++{
++ mutex_lock(&clocks_mutex);
++ list_del(&clk->node);
++ mutex_unlock(&clocks_mutex);
++}
++EXPORT_SYMBOL(clk_unregister);
+
+ static unsigned long spmf_mult(void)
+ {
+@@ -236,16 +256,15 @@
+
+ static unsigned long devtree_getfreq(char *clockname)
+ {
+- struct device_node *np;
+- const unsigned int *prop;
++ struct device_node *node;
++ const unsigned int *fp;
+ unsigned int val = 0;
+
+- np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
+- if (np) {
+- prop = of_get_property(np, clockname, NULL);
+- if (prop)
+- val = *prop;
+- of_node_put(np);
++ node = of_find_node_by_type(NULL, "soc");
++ if (node) {
++ fp = of_get_property(node, clockname, NULL);
++ if (fp)
++ val = of_read_ulong(fp, 1);
+ }
+ return val;
+ }
+@@ -254,13 +273,21 @@
+ {
+ unsigned long rate;
+
+- rate = devtree_getfreq("bus-frequency");
++ rate = devtree_getfreq("ref-frequency");
+ if (rate == 0) {
+- printk(KERN_ERR "No bus-frequency in dev tree\n");
+- clk->rate = 0;
+- return;
++ /*
++ * no reference clock in device tree
++ * get ips clock freq and go backwards from there
++ */
++ rate = devtree_getfreq("bus-frequency");
++ if (rate == 0) {
++ printk(KERN_WARNING
++ "No bus-frequency in dev tree using 66MHz\n");
++ clk->rate = 66000000;
++ return;
++ }
++ clk->rate = ips_to_ref(rate);
+ }
+- clk->rate = ips_to_ref(rate);
+ }
+
+ static struct clk ref_clk = {
+@@ -661,8 +688,11 @@
+ struct device_node *np;
+ const u32 *cell_index;
+ struct of_device *ofdev;
+-
++#ifdef CONFIG_PPC_MPC5125
++ for_each_compatible_node(np, NULL, "fsl,mpc5125-psc") {
++#else
+ for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") {
++#endif
+ cell_index = of_get_property(np, "cell-index", NULL);
+ if (cell_index) {
+ int pscnum = *cell_index;
+@@ -686,28 +716,97 @@
+ }
+ }
+
+-static struct clk_interface mpc5121_clk_functions = {
+- .clk_get = mpc5121_clk_get,
+- .clk_enable = mpc5121_clk_enable,
+- .clk_disable = mpc5121_clk_disable,
+- .clk_get_rate = mpc5121_clk_get_rate,
+- .clk_put = mpc5121_clk_put,
+- .clk_round_rate = mpc5121_clk_round_rate,
+- .clk_set_rate = mpc5121_clk_set_rate,
+- .clk_set_parent = NULL,
+- .clk_get_parent = NULL,
+-};
++unsigned long round_rate(unsigned long rate)
++{
++ unsigned long new_rate;
++ new_rate = (unsigned long)((rate + ROUND_1MHZ) / ROUND_1MHZ) *
++ ROUND_1MHZ;
++ return new_rate;
++}
++
++/*
++ * mscan clock rate calculation
++ */
++static void mscan_calc_rate(struct clk *clk, int mscannum, struct device_node *np)
++{
++ unsigned long mscanclk_src = sys_clk.rate;
++ unsigned long mscanclk_div;
++
++ /*
++ * If the divider is the reset default of all 1's then
++ * we know u-boot and/or board setup has not
++ * done anything so set up a sane default
++ */
++ if (((clockctl->mccr[mscannum] >> 17) & 0x7fff) == 0x7fff) {
++ /* disable */
++ clockctl->mccr[mscannum] = 0x0;
++ /* src is sysclk, divider is 4 */
++ clockctl->mccr[mscannum] = 0x3 << 17;
++ /* enable */
++ clockctl->mccr[mscannum] |= 0x10000;
++ }
++
++ switch ((clockctl->mccr[mscannum] >> 14) & 0x3) {
++ case 0:
++ mscanclk_src = round_rate(sys_clk.rate);
++ break;
++ case 1:
++ mscanclk_src = round_rate(ref_clk.rate);
++ break;
++ case 2:
++ mscanclk_src = round_rate(psc_mclk_in.rate);
++ break;
++ case 3:
++ mscanclk_src = round_rate(spdif_txclk.rate);
++ break;
++ }
++
++ mscanclk_div = ((clockctl->mccr[mscannum] >> 17) & 0x7fff) + 1;
++ clk->rate = mscanclk_src / mscanclk_div;
++}
++struct clk mscan_clks[4];
++
++/*
++ * Find all silicon rev2 mscan nodes in device tree and assign a clock
++ * with name "mscan%d_clk" and dev pointing at the device
++ * returned from of_find_device_by_node
++ */
++static void mscan_clks_init(void)
++{
++ struct device_node *np;
++ const u32 *cell_index;
++ struct of_device *ofdev;
++
++ for_each_compatible_node(np, NULL, "fsl,mpc5121rev2-mscan") {
++ cell_index = of_get_property(np, "cell-index", NULL);
++ if (cell_index) {
++ int mscannum = *cell_index;
++ struct clk *clk = &mscan_clks[mscannum];
++
++ clk->flags = CLK_HAS_RATE;
++ ofdev = of_find_device_by_node(np);
++ clk->dev = &ofdev->dev;
++ mscan_calc_rate(clk, mscannum, np);
++ sprintf(clk->name, "mscan%d_clk", mscannum);
++ printk("register :%s \n",clk->name);
++ clk_register(clk);
++ }
++ }
++}
+
+ static int
+ mpc5121_clk_init(void)
+ {
+ struct device_node *np;
+
+- np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+- if (np) {
+- clockctl = of_iomap(np, 0);
+- of_node_put(np);
+- }
++ /* look for rev2 first then rev1 */
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121rev2-clock");
++ if (np)
++ rev2_silicon++;
++ else
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
++ clockctl = of_iomap(np, 0);
++ of_node_put(np);
+
+ if (!clockctl) {
+ printk(KERN_ERR "Could not map clock control registers\n");
+@@ -716,12 +815,13 @@
+
+ rate_clks_init();
+ psc_clks_init();
++ if (rev2_silicon)
++ mscan_clks_init();
+
+ /* leave clockctl mapped forever */
+ /*iounmap(clockctl); */
+ DEBUG_CLK_DUMP();
+ clocks_initialized++;
+- clk_functions = mpc5121_clk_functions;
+ return 0;
+ }
+
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/Kconfig linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/Kconfig
+--- linux-2.6.29/arch/powerpc/platforms/512x/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -6,9 +6,25 @@
+ select PPC_PCI_CHOICE
+ select FSL_PCI if PCI
+
++config PPC_MPC5125
++ bool
++ select PPC_MPC512x
++ select USB_ARCH_HAS_EHCI
++ select USB_EHCI_BIG_ENDIAN_DESC
++ select USB_EHCI_BIG_ENDIAN_MMIO
++ select USB_FSL_BIG_ENDIAN_DESC
++ select PPC_INDIRECT_PCI
++ default n
++
+ config PPC_MPC5121
+ bool
+ select PPC_MPC512x
++ select USB_ARCH_HAS_EHCI
++ select USB_EHCI_BIG_ENDIAN_DESC
++ select USB_EHCI_BIG_ENDIAN_MMIO
++ select USB_FSL_BIG_ENDIAN_DESC
++ select PPC_INDIRECT_PCI
++ default n
+
+ config MPC5121_ADS
+ bool "Freescale MPC5121E ADS"
+@@ -18,6 +34,19 @@
+ select MPC5121_ADS_CPLD
+ help
+ This option enables support for the MPC5121E ADS board.
++config PPC_MERGE
++ bool "Freescale MPC5121 PORTING TO MPC5125 tower"
++ depends on MPC5125_TWR
++ default n
++config MPC5125_TWR
++ bool "Freescale MPC5125 tower"
++ depends on PPC_MULTIPLATFORM && PPC32
++ select DEFAULT_UIMAGE
++ select PPC_MPC5125
++ select PPC_MERGE
++ help
++ This option enables support for the MPC5121E ADS board.
++
+
+ config MPC5121_GENERIC
+ bool "Generic support for simple MPC5121 based boards"
+@@ -29,4 +58,24 @@
+ which do not need custom platform specific setup.
+
+ Compatible boards include: Protonic LVT base boards (ZANMCU
+- and VICVT2).
++ and VICVT2).
++
++config MPC5121_ADS_HIB
++ bool "Hibernate Support for ADS5121"
++ depends on PM && ARCH_SUSPEND_POSSIBLE
++ ---help---
++ This option enables support for Hibernate on ADS5121 board
++ (based on MPC5121e). The Hibernate is entered by writing
++ "mem" to /sys/power/state, while Deep-Sleep mode is
++ supported by writing "standby" to /sys/power/state.
++ default n
++
++
++config MPC5121_PM_TEST
++ bool "Lowlevel test for Freescale MPC5121E Power Management"
++ depends on PM
++ ---help---
++ Say yes here to enable low level powermanagement test code.
++ It uses the MSCAN modules so the 5121 MSCAN driver must
++ be turned off.
++
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/Makefile linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/Makefile
+--- linux-2.6.29/arch/powerpc/platforms/512x/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -1,6 +1,13 @@
+ #
+ # Makefile for the Freescale PowerPC 512x linux kernel.
+ #
+-obj-y += clock.o mpc512x_shared.o
++obj-y += clock.o mpc512x_shared.o mpc5121_usb.o mpc5121_pscgpio.o
++obj-$(CONFIG_SPI) += mpc5121_spi.o
+ obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o mpc5121_ads_cpld.o
++obj-$(CONFIG_MPC5125_TWR) +=mpc5125_twr.o
+ obj-$(CONFIG_MPC5121_GENERIC) += mpc5121_generic.o
++obj-$(CONFIG_PM) += mpc512x_pm.o mpc512x.o
++ifeq ($(CONFIG_MPC5121_ADS_HIB),y)
++ obj-$(CONFIG_PM) += ads5121_pm.o ads5121_sleep.o
++endif
++obj-$(CONFIG_MPC5121_PM_TEST) += mpc512x_pm_test.o
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/mpc5121_ads.c linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc5121_ads.c
+--- linux-2.6.29/arch/powerpc/platforms/512x/mpc5121_ads.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc5121_ads.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,71 +0,0 @@
+-/*
+- * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc. All rights reserved.
+- *
+- * Author: John Rigby, <jrigby@freescale.com>, Thur Mar 29 2007
+- *
+- * Description:
+- * MPC5121 ADS board setup
+- *
+- * This is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/io.h>
+-#include <linux/of_platform.h>
+-
+-#include <asm/machdep.h>
+-#include <asm/ipic.h>
+-#include <asm/prom.h>
+-#include <asm/time.h>
+-
+-#include <sysdev/fsl_pci.h>
+-
+-#include "mpc512x.h"
+-#include "mpc5121_ads.h"
+-
+-static void __init mpc5121_ads_setup_arch(void)
+-{
+-#ifdef CONFIG_PCI
+- struct device_node *np;
+-#endif
+- printk(KERN_INFO "MPC5121 ADS board from Freescale Semiconductor\n");
+- /*
+- * cpld regs are needed early
+- */
+- mpc5121_ads_cpld_map();
+-
+-#ifdef CONFIG_PCI
+- for_each_compatible_node(np, "pci", "fsl,mpc5121-pci")
+- mpc83xx_add_bridge(np);
+-#endif
+-}
+-
+-static void __init mpc5121_ads_init_IRQ(void)
+-{
+- mpc512x_init_IRQ();
+- mpc5121_ads_cpld_pic_init();
+-}
+-
+-/*
+- * Called very early, MMU is off, device-tree isn't unflattened
+- */
+-static int __init mpc5121_ads_probe(void)
+-{
+- unsigned long root = of_get_flat_dt_root();
+-
+- return of_flat_dt_is_compatible(root, "fsl,mpc5121ads");
+-}
+-
+-define_machine(mpc5121_ads) {
+- .name = "MPC5121 ADS",
+- .probe = mpc5121_ads_probe,
+- .setup_arch = mpc5121_ads_setup_arch,
+- .init = mpc512x_declare_of_platform_devices,
+- .init_IRQ = mpc5121_ads_init_IRQ,
+- .get_irq = ipic_get_irq,
+- .calibrate_decr = generic_calibrate_decr,
+-};
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/mpc5121_pscgpio.c linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc5121_pscgpio.c
+--- linux-2.6.29/arch/powerpc/platforms/512x/mpc5121_pscgpio.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc5121_pscgpio.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,172 @@
++/*
++ * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * Author: John Rigby, <jrigby@freescale.com>, April 2008
++ *
++ * Description:
++ * MPC5121 psc gpio helper routines
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/of_platform.h>
++
++#include <asm/io.h>
++
++/*
++ * Helper routines for pscN_M pins.
++ * Allow for making the psc pins into GPIO outputs and
++ * driving them high or low.
++ * These are for use by the various psc drivers (Audio, SPI, whatever)
++ * so they don't have to be polluted with IOCTL and GPIO knowledge.
++ *
++ * TODO: Make a full fledged GPIO driver.
++ */
++
++/*
++ * psc/pin to gpio number map
++ * psc pin gpio
++ * ==========================
++ * 0 0 8 (psc % 5)*4 + 8 + pin
++ * 0 1 9
++ * 0 2 10
++ * 0 3 11
++ * 0 4 0 psc % 8
++ * 1 0 12
++ * 1 1 13
++ * 1 2 14
++ * 1 3 15
++ * 1 4 1
++ * 2 0 16
++ * ....
++ * pin 4 cycles through GPIOs 0-7
++ * other pins cycle through GPIOs 8-27
++ * ....
++ * 10 2 10
++ * 10 3 11
++ * 10 4 2
++ * 11 0 12
++ * 11 1 13
++ * 11 2 14
++ * 11 3 15
++ * 11 4 3
++ */
++
++#define PSC_TO_GPIO(psc, pin) ( \
++ pin == 4 ? \
++ (psc % 8) \
++ : \
++ (psc % 5) * 4 + 8 + pin \
++)
++#ifdef CONFIG_PPC_MPC5125
++#define PSC_TO_IOCTL_OFFSET(psc, pin) ( \
++ 0x76 \
++ + psc * (5*sizeof(u8)) \
++ + pin * sizeof(u8) \
++)
++#else
++#define PSC_IOCTL_SIZE (5 * sizeof(long))
++
++#define PSC_TO_IOCTL_OFFSET(psc, pin) ( \
++ 0x20C \
++ + psc * PSC_IOCTL_SIZE \
++ + pin * sizeof(long) \
++)
++#endif
++static void __iomem *gpioctl;
++#define GPIODIR 0
++#define GPIODAT 8
++static void __iomem *ioctl;
++
++void mpc5121_pscgpio_make_gpio(int psc, int pin)
++{
++ out_be32(ioctl + PSC_TO_IOCTL_OFFSET(psc, pin), 0x00000183);
++ setbits32(gpioctl+GPIODIR, 0x80000000 >> PSC_TO_GPIO(psc, pin));
++}
++EXPORT_SYMBOL(mpc5121_pscgpio_make_gpio);
++
++void mpc5121_pscgpio_make_psc(int psc, int pin)
++{
++#ifdef CONFIG_PPC_MPC5125
++ out_8(ioctl + PSC_TO_IOCTL_OFFSET(psc, pin), pin == 0 ? 0x7 : 0x03);
++#else
++ out_be32(ioctl + PSC_TO_IOCTL_OFFSET(psc, pin), pin == 0 ? 0x00000007 : 0x00000003);
++#endif
++}
++EXPORT_SYMBOL(mpc5121_pscgpio_make_psc);
++
++void mpc5121_pscgpio_make_psc_pull_up(int psc, int pin)
++{
++#ifdef CONFIG_PPC_MPC5125
++ out_8(ioctl + PSC_TO_IOCTL_OFFSET(psc, pin), pin == 0 ? 0x1f : 0x1b);
++#else
++ out_be32(ioctl + PSC_TO_IOCTL_OFFSET(psc, pin), pin == 0 ? 0x00000007 : 0x00000003);
++#endif
++}
++EXPORT_SYMBOL(mpc5121_pscgpio_make_psc_pull_up);
++
++#ifdef CONFIG_PPC_MPC5125
++void mpc5125_psc_io_controller_set(int psc, int pin,unsigned char value)
++{
++ out_8(ioctl + PSC_TO_IOCTL_OFFSET(psc, pin), value);
++}
++EXPORT_SYMBOL(mpc5125_psc_io_controller_set);
++void mpc5125_io_controller_set(int offset,unsigned char value)
++{
++ out_8(ioctl + offset, value);
++}
++EXPORT_SYMBOL(mpc5125_io_controller_set);
++#endif
++void mpc5121_pscgpio_pin_high(int psc, int pin)
++{
++ setbits32(gpioctl+GPIODAT, 0x80000000 >> PSC_TO_GPIO(psc, pin));
++}
++EXPORT_SYMBOL(mpc5121_pscgpio_pin_high);
++
++void mpc5121_pscgpio_pin_low(int psc, int pin)
++{
++ clrbits32(gpioctl+GPIODAT, 0x80000000 >> PSC_TO_GPIO(psc, pin));
++}
++EXPORT_SYMBOL(mpc5121_pscgpio_pin_low);
++
++static int __init mpc5121_pscgpio_init(void)
++{
++ struct device_node *np;
++#ifdef CONFIG_PPC_MPC5125
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5125-ioctl");
++#else
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-ioctl");
++#endif
++ if (np) {
++ ioctl = of_iomap(np, 0);
++ of_node_put(np);
++ }
++/*enable nand_ce1*/
++ out_8(ioctl+0x08,0x3b);
++#ifdef CONFIG_PPC_MPC5125
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5125-gpio");
++#else
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-gpio");
++#endif
++ if (np) {
++ gpioctl = of_iomap(np, 0);
++ of_node_put(np);
++ }
++
++ /* don't unmap these, they will be used later */
++ /*
++ * iounmap(ioctl);
++ * iounmap(gpioctl);
++ */
++
++ printk(KERN_INFO "mapped ioctl to %p and gpioctl to %p\n",
++ (void *)ioctl, (void *)gpioctl);
++
++ return 0;
++}
++
++arch_initcall(mpc5121_pscgpio_init);
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/mpc5121_spi.c linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc5121_spi.c
+--- linux-2.6.29/arch/powerpc/platforms/512x/mpc5121_spi.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc5121_spi.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,188 @@
++/*
++ * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * Author: John Rigby, <jrigby@freescale.com>, May 2008
++ *
++ * Description:
++ * MPC5121 spi setup
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/of_platform.h>
++#include <linux/spi/spi.h>
++#include <linux/fsl_devices.h>
++
++#include <asm/io.h>
++
++#include "mpc512x.h"
++
++static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
++{
++ const u32 *prop;
++ int len;
++
++ prop = of_get_property(np, name, &len);
++ if (prop && len == 4)
++ return *prop;
++ return def;
++}
++
++#define GET_INT_PROP(pd, np, propname) \
++ (pd->propname = get_int_prop(np, #propname, pd->propname))
++
++
++#if 0/*defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)*/
++#define CFG_ADS7846
++#include <linux/spi/ads7846.h>
++#endif
++
++#if 0 /* CFG_ADS7846*/
++
++static struct ads7846_platform_data mpc5121eads_ads7846_platform_data __initdata = {
++ .model = 7843,
++ .vref_delay_usecs = 100,
++ .x_plate_ohms = 500,
++ .y_plate_ohms = 500,
++ .get_pendown_state = mpc5121ads_get_pendown_state,
++};
++
++static void __init *ads7846_get_pdata(struct device_node *np)
++{
++ struct ads7846_platform_data *pd = &mpc5121eads_ads7846_platform_data;
++ GET_INT_PROP(pd, np, model);
++ GET_INT_PROP(pd, np, vref_delay_usecs);
++ GET_INT_PROP(pd, np, x_plate_ohms);
++ GET_INT_PROP(pd, np, y_plate_ohms);
++
++ return pd;
++}
++#endif
++
++struct spi_driver_device {
++ char *of_device;
++ char *modalias;
++ int needirq;
++ void *(*get_platform_data)(struct device_node *);
++};
++
++static struct spi_driver_device spi_devices[] __initdata = {
++#ifdef CONFIG_SPI_SPIDEV
++ {
++ .of_device = "linux,spidev",
++ .modalias = "spidev",
++ },
++#endif
++#ifdef CFG_ADS7846
++ {
++ .of_device = "ti,ads7846",
++ .modalias = "ads7846",
++ .needirq = 1,
++ .get_platform_data = ads7846_get_pdata,
++ },
++#endif
++#ifdef CONFIG_SND_SOC_AD1939
++ {
++ .of_device = "ad,ad1938",
++ .modalias = "AD1939",
++ },
++ {
++ .of_device = "ad,ad1939",
++ .modalias ="AD1939",
++ },
++#endif
++};
++
++static int __init find_spi_driver(struct device_node *node,
++ struct spi_board_info *info)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(spi_devices); i++) {
++ if (!of_device_is_compatible(node, spi_devices[i].of_device))
++ continue;
++ if (spi_devices[i].needirq && info->irq == NO_IRQ) {
++ printk(KERN_WARNING "mpc5121_spi.c %s needs valid irq\n",
++ spi_devices[i].modalias);
++ return -EINVAL;
++ }
++ /*
++ if (strlcpy(info->modalias, spi_devices[i].modalias,
++ KOBJ_NAME_LEN) >= KOBJ_NAME_LEN)
++ */
++ if (strlcpy(info->modalias, spi_devices[i].modalias,
++ 20) >= 20)
++ return -ENOMEM;
++ if (spi_devices[i].get_platform_data)
++ info->platform_data = spi_devices[i].get_platform_data(node);
++ return 0;
++ }
++ return -ENODEV;
++}
++
++static int of_device_add_data(struct of_device *of_dev, const void *data, size_t size)
++{
++ void *d;
++
++ d = kmalloc(size, GFP_KERNEL);
++ if (d) {
++ memcpy(d, data, size);
++ of_dev->dev.platform_data = d;
++ }
++ return d ? 0 : -ENOMEM;
++}
++
++static void __init register_spi_bus(struct device_node *spi_node, int bus_num)
++{
++ struct device_node *node = NULL;
++ struct of_device *of_dev;
++ struct fsl_spi_platform_data pdata = {
++ .bus_num = bus_num,
++ .max_chipselect = 255,
++ };
++
++ of_dev = of_find_device_by_node(spi_node);
++ if (of_dev) {
++ of_device_add_data(of_dev, &pdata, sizeof(pdata));
++ }
++
++ while ((node = of_get_next_child(spi_node, node))) {
++ struct spi_board_info *bp, info = {};
++
++ bp = &info;
++
++ bp->bus_num = bus_num;
++ GET_INT_PROP(bp, node, chip_select);
++ GET_INT_PROP(bp, node, max_speed_hz);
++ info.irq = irq_of_parse_and_map(node, 0);
++
++ if (find_spi_driver(node, &info) < 0)
++ continue;
++
++ spi_register_board_info(&info, 1);
++ }
++}
++
++static int __init mpc5121_spi_init(void)
++{
++ struct device_node *np;
++ int bus_num;
++
++ for_each_compatible_node(np, NULL, "fsl,mpc5121-psc-spi") {
++ bus_num = get_int_prop(np, "cell-index", -1);
++ if (bus_num < 0 || bus_num > 11) {
++ printk(KERN_WARNING "mpc5121_spi.c no cell-index spi node, skipping\n");
++ continue;
++ }
++ register_spi_bus(np, bus_num);
++ of_node_put(np);
++ }
++
++ return 0;
++}
++
++arch_initcall(mpc5121_spi_init);
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/mpc5121_usb.c linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc5121_usb.c
+--- linux-2.6.29/arch/powerpc/platforms/512x/mpc5121_usb.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc5121_usb.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,107 @@
++/*
++ * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * Author: Duck, <duck@freescale.com>, Tue Oct 2 2007
++ *
++ * Description:
++ * MPC5121 USB platform-specific routines
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++
++#include <linux/clk.h>
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/errno.h>
++#include <linux/fsl_devices.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/stddef.h>
++
++#define USBGENCTRL 0x200 /* NOTE: big endian */
++#define GC_WU_INT_CLR (1 << 5) /* Wakeup int clear */
++#define GC_ULPI_SEL (1 << 4) /* ULPI i/f select (usb0 only)*/
++#define GC_PPP (1 << 3) /* Port Power Polarity */
++#define GC_PFP (1 << 2) /* Power Fault Polarity */
++#define GC_WU_ULPI_EN (1 << 1) /* Wakeup on ULPI event */
++#define GC_WU_IE (1 << 1) /* Wakeup interrupt enable */
++
++#define ISIPHYCTRL 0x204 /* NOTE: big endian */
++#define PHYCTRL_PHYE (1 << 4) /* On-chip UTMI PHY enable */
++#define PHYCTRL_BSENH (1 << 3) /* Bit Stuff Enable High */
++#define PHYCTRL_BSEN (1 << 2) /* Bit Stuff Enable */
++#define PHYCTRL_LSFE (1 << 1) /* Line State Filter Enable */
++#define PHYCTRL_PXE (1 << 0) /* PHY oscillator enable */
++
++
++int usb_platform_mph_init(struct platform_device *pdev)
++{
++ return -ENODEV; /* no MPH port on 5121 */
++}
++EXPORT_SYMBOL_GPL(usb_platform_mph_init);
++
++
++void usb_platform_mph_uninit(struct fsl_usb2_platform_data *pdata)
++{
++}
++EXPORT_SYMBOL_GPL(usb_platform_mph_uninit);
++
++static struct clk *dr_clk;
++static int dr_used;
++
++int usb_platform_dr_init(struct platform_device *pdev)
++{
++ struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
++
++ pr_debug("%s: pdata %p\n\n", __FUNCTION__, pdata);
++
++ /* enable the clock if we haven't already */
++ if (!dr_used) {
++ dr_clk = clk_get(&pdev->dev, "usb2_clk");
++ if (IS_ERR(dr_clk)) {
++ dev_err(&pdev->dev, "usb: clk_get failed\n");
++ return -ENODEV;
++ }
++ clk_enable(dr_clk);
++ }
++ dr_used++;
++
++ pdata->big_endian_desc = 1;
++ pdata->le_setup_buf = 1;
++ pdata->es = 1;
++
++ if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
++ void __iomem *base = pdata->regs;
++
++ out_be32(base + ISIPHYCTRL, PHYCTRL_PHYE | PHYCTRL_PXE);
++ out_be32(base + USBGENCTRL, GC_PPP | GC_PFP);
++ }
++ pr_debug("%s: success\n", __FUNCTION__);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(usb_platform_dr_init);
++
++void usb_platform_dr_uninit(struct fsl_usb2_platform_data *pdata)
++{
++ pr_debug("%s\n", __FUNCTION__);
++
++ pdata->regs = NULL;
++ // DDD no longer used pdata->r_start = pdata->r_len = 0;
++
++ dr_used--;
++ if (!dr_used) {
++ clk_disable(dr_clk);
++ clk_put(dr_clk);
++ dr_clk = NULL;
++ }
++}
++EXPORT_SYMBOL_GPL(usb_platform_dr_uninit);
++
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/mpc5125_twr.c linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc5125_twr.c
+--- linux-2.6.29/arch/powerpc/platforms/512x/mpc5125_twr.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc5125_twr.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,584 @@
++/*
++ * Provider: LimePC Multimedia Technologies Co., Limited
++ * Date:02/02/2010
++ * autor:Cloudy Chen <chen_yunsong@mtcera.com>
++ * Description:
++ * MPC5125 tower board setup
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/of_platform.h>
++
++#include <asm/machdep.h>
++#include <asm/ipic.h>
++#include <asm/prom.h>
++#include <asm/time.h>
++
++#include <asm/mpc512x.h>
++#include <sysdev/fsl_soc.h>
++
++#include <linux/bootmem.h>
++#include <asm/rheap.h>
++
++#include "mpc512x.h"
++
++#ifdef DEBUG
++#define DPRINTK(fmt, args...) printk("%s: " fmt,__FUNCTION__,## args)
++#else
++#define DPRINTK(fmt, args...)
++#endif
++asmlinkage long sys_mtc_system_call( int cmd, int arg)
++{
++ void __user *argp = (void __user *)arg;
++ int error=-1;
++ return error;
++}
++static u32 get_busfreq(void)
++{
++ struct device_node *node;
++
++ u32 fs_busfreq=0;
++ node = of_find_node_by_type(NULL, "cpu");
++ if (node) {
++ unsigned int size;
++ const unsigned int *prop = of_get_property(node,"bus-frequency", &size);
++ if (prop)
++ fs_busfreq = *prop;
++ of_node_put(node);
++ };
++ return fs_busfreq;
++}
++
++#ifdef CONFIG_FB_FSL_DIU
++#define DISABLE_RH_MEMORY 0
++
++static rh_block_t diu_rh_block[16];
++static rh_info_t diu_rh_info;
++static unsigned long diu_size = 1280 * 1024 * 4; /* One 1280x1024 buffer */
++static void *diu_mem;
++
++unsigned int platform_get_pixel_format(unsigned int bits_per_pixel,
++ int monitor_port,
++ char byte_flip)
++{
++ unsigned int pix_fmt;
++
++ if (bits_per_pixel == 32) {
++ if (byte_flip)
++ pix_fmt = 0x88883316;
++ else
++ pix_fmt = 0x88883306;
++ } else if (bits_per_pixel == 24) {
++ pix_fmt = 0x88082219;
++ } else if (bits_per_pixel == 16) {
++ if (byte_flip)
++ pix_fmt = 0x65053118;
++ else
++ pix_fmt = 0x65052908;
++ } else /* bits_per_pixel == 8, need to enable pallete table */
++ pix_fmt = 0x00000400;
++
++ return pix_fmt;
++}
++EXPORT_SYMBOL(platform_get_pixel_format);
++
++void platform_set_gamma_table(int monitor_port, char *gamma_table_base)
++{
++}
++EXPORT_SYMBOL(platform_set_gamma_table);
++
++void platform_set_monitor_port(int monitor_port)
++{
++}
++EXPORT_SYMBOL(platform_set_monitor_port);
++
++void platform_set_pixel_clock(unsigned int pixclock)
++{
++ u32 * clkdvdr, temp;
++ /* variables for pixel clock calcs */
++ unsigned long bestval, bestfreq, speed_ccb, minpixclock, maxpixclock, pixval;
++ long err;
++ int i;
++
++ clkdvdr = (u32 *)ioremap(get_immrbase() + 0xf0c, sizeof(u32));
++
++ /* Pixel Clock configuration */
++ DPRINTK("DIU: Bus Frequency = %d\n",get_busfreq());
++ speed_ccb = get_busfreq() * 4;
++
++ /* Calculate the pixel clock with the smallest error */
++ /* calculate the following in steps to avoid overflow */
++ DPRINTK("DIU pixclock in ps - %d\n",pixclock);
++ temp = 1;
++ temp *= 1000000000;
++ temp /= pixclock;
++ temp *= 1000;
++ pixclock = temp;
++ DPRINTK("DIU pixclock freq - %lu\n",pixclock);
++
++ temp *= 5;
++ temp /= 100; /* pixclock * 0.05 */
++ DPRINTK("deviation = %d\n", temp);
++ minpixclock = pixclock - temp;
++ maxpixclock = pixclock + temp;
++ DPRINTK("DIU minpixclock - %lu\n", minpixclock);
++ DPRINTK("DIU maxpixclock - %lu\n", maxpixclock);
++ pixval = speed_ccb/pixclock;
++ DPRINTK("DIU pixval = %lu\n",pixval);
++
++ err = 100000000;
++ bestval = pixval;
++ DPRINTK("DIU bestval = %lu\n", bestval);
++
++ bestfreq = 0;
++ for (i = -1; i <= 1; i++) {
++ temp = speed_ccb / (pixval+i);
++ DPRINTK("DIU test pixval i= %d, pixval=%lu, temp freq. = %u\n",i,pixval,temp);
++ if ((temp < minpixclock) || (temp > maxpixclock))
++ DPRINTK("DIU exceeds monitor range (%lu to %lu)\n",
++ minpixclock,maxpixclock);
++ else if (abs(temp - pixclock) < err) {
++ DPRINTK("Entered the else if block %d\n", i);
++ err = abs(temp - pixclock);
++ bestval = pixval+i;
++ bestfreq = temp;
++ }
++ }
++
++ DPRINTK("DIU chose = %lx\n", bestval);
++ DPRINTK("DIU error = %ld\n NomPixClk ", err);
++ DPRINTK("DIU: Best Freq = %lx\n",bestfreq);
++ /* Modify PXCLK in GUTS CLKDVDR */
++ DPRINTK("DIU: Current value of CLKDVDR = 0x%08x\n",(*clkdvdr));
++ temp = (* clkdvdr) & 0xffffff00;
++ * clkdvdr = temp | (bestval & 0xFF);
++ DPRINTK("DIU: Modified value of CLKDVDR = 0x%08x\n",(*clkdvdr));
++}
++EXPORT_SYMBOL(platform_set_pixel_clock);
++
++ssize_t platform_show_monitor_port(int monitor_port, char * buf)
++{
++ return snprintf(buf, PAGE_SIZE, "0 - 5121ads DVI & LCD\n");
++}
++EXPORT_SYMBOL(platform_show_monitor_port);
++
++int platform_set_sysfs_monitor_port(int val)
++{
++ return 0;
++}
++EXPORT_SYMBOL(platform_set_sysfs_monitor_port);
++
++static void __init preallocate_diu_videomemory(void)
++{
++#if DISABLE_RH_MEMORY
++#else
++ printk(KERN_INFO "%s: diu_size=%lu\n", __FUNCTION__, diu_size);
++
++ diu_mem = __alloc_bootmem(diu_size, 8, 0);
++
++ if (!diu_mem) {
++ printk(KERN_ERR "fsl-diu: cannot allocate %lu bytes\n",
++ diu_size);
++ return;
++ }
++
++ printk(KERN_INFO "%s: diu_mem=%p\n", __FUNCTION__, diu_mem);
++
++ rh_init(&diu_rh_info, 4096, ARRAY_SIZE(diu_rh_block), diu_rh_block);
++ rh_attach_region(&diu_rh_info, (unsigned long) diu_mem, diu_size);
++#endif
++}
++
++void *fsl_diu_alloc(unsigned long size, unsigned long *phys)
++{
++ void *virt;
++#if DISABLE_RH_MEMORY
++ virt=dma_alloc_coherent(NULL, size,
++ phys, GFP_KERNEL|GFP_DMA);
++#else
++
++ printk(KERN_ERR "%s: size=%lu\n", __FUNCTION__, size);
++ if (!diu_mem) {
++ printk(KERN_INFO "%s: no diu_mem\n", __FUNCTION__);
++ return NULL;
++ }
++
++ virt = (void *) rh_alloc(&diu_rh_info, size, "DIU");
++ if (virt)
++ *phys = virt_to_bus(virt);
++
++ printk(KERN_DEBUG "%s:%u rh virt=%p phys=%lx\n",
++ __FUNCTION__, __LINE__, virt, *phys);
++#endif
++ return virt;
++}
++EXPORT_SYMBOL(fsl_diu_alloc);
++
++void fsl_diu_free(void *p, unsigned long size)
++{
++#if DISABLE_RH_MEMORY
++ if(!p)return;
++ dma_free_coherent(0, size, p, 0);
++#else
++ printk(KERN_DEBUG "%s: p=%p size=%lu\n", __FUNCTION__, p, size);
++
++ if (!p)
++ return;
++
++ if ((p >= diu_mem) && (p < (diu_mem + diu_size))) {
++ printk(KERN_DEBUG "%s:%u rh\n", __FUNCTION__, __LINE__);
++ rh_free(&diu_rh_info, (unsigned long) p);
++ } else {
++ printk(KERN_DEBUG "%s:%u dma\n", __FUNCTION__, __LINE__);
++ dma_free_coherent(0, size, p, 0);
++ }
++#endif
++}
++EXPORT_SYMBOL(fsl_diu_free);
++
++static int __init early_parse_diufb(char *p)
++{
++ if (!p)
++ return 1;
++
++ diu_size = _ALIGN_UP(memparse(p, &p), 8);
++
++ printk(KERN_INFO "%s: diu_size=%lu\n", __FUNCTION__, diu_size);
++
++ return 0;
++}
++early_param("diufb", early_parse_diufb);
++
++#else
++
++#define preallocate_diu_videomemory() do { } while (0)
++
++#endif
++
++/**
++ * mpc512x_find_ips_freq - Find the IPS bus frequency for a device
++ * @node: device node
++ *
++ * Returns IPS bus frequency, or 0 if the bus frequency cannot be found.
++ */
++unsigned long
++mpc512x_find_ips_freq(struct device_node *node)
++{
++ struct device_node *np;
++ const unsigned int *p_ips_freq = NULL;
++
++ of_node_get(node);
++ while (node) {
++ p_ips_freq = of_get_property(node, "bus-frequency", NULL);
++ if (p_ips_freq)
++ break;
++
++ np = of_get_parent(node);
++ of_node_put(node);
++ node = np;
++ }
++ if (node)
++ of_node_put(node);
++
++ return p_ips_freq ? *p_ips_freq : 0;
++}
++EXPORT_SYMBOL(mpc512x_find_ips_freq);
++#define DEFAULT_FIFO_SIZE 16
++
++static unsigned int get_fifo_size(struct device_node *np, int psc_num, char *fifo_name)
++{
++ const unsigned int *fp;
++
++ fp = of_get_property(np, fifo_name, NULL);
++ if (fp)
++ return *fp;
++ printk(KERN_WARNING "no %s property for psc%d defaulting to %d\n",
++ fifo_name, psc_num, DEFAULT_FIFO_SIZE);
++ return DEFAULT_FIFO_SIZE;
++}
++
++static int psc_fifo_base[12];
++static void mpc5125_psc_fifo_init(char *name)
++{
++ struct device_node *np;
++ const u32 *cell_index;
++ int fifobase = 0; /* current fifo address in 32 bit words */
++ char *default_psc = "fsl,mpc5125-psc";
++ char *psc_name;
++
++ if (name)
++ psc_name = name;
++ else
++ psc_name = default_psc;
++
++ for_each_compatible_node(np, NULL, psc_name) {
++ cell_index = of_get_property(np, "cell-index", NULL);
++ if (cell_index) {
++ int psc_num = *cell_index;
++ unsigned int tx_fifo_size;
++ unsigned int rx_fifo_size;
++ void __iomem *psc;
++
++ tx_fifo_size = get_fifo_size(np, psc_num, "tx-fifo-size");
++ rx_fifo_size = get_fifo_size(np, psc_num, "rx-fifo-size");
++
++ /* size in register is in 4 byte words */
++ tx_fifo_size /= 4;
++ rx_fifo_size /= 4;
++
++ psc = of_iomap(np, 0);
++
++ if(strcmp(psc_name, default_psc)) {
++ fifobase = psc_fifo_base[psc_num];
++ /* tx fifo size register is at 0x9c and rx at 0xdc */
++ out_be32(psc + 0x9c, (fifobase << 16) | tx_fifo_size);
++ fifobase += tx_fifo_size;
++ out_be32(psc + 0xdc, (fifobase << 16) | rx_fifo_size);
++ } else {
++ psc_fifo_base[psc_num] = fifobase;
++ /* tx fifo size register is at 0x9c and rx at 0xdc */
++ out_be32(psc + 0x9c, (fifobase << 16) | tx_fifo_size);
++ fifobase += tx_fifo_size;
++ out_be32(psc + 0xdc, (fifobase << 16) | rx_fifo_size);
++ fifobase += rx_fifo_size;
++ }
++ printk("PSC%d psc_fifo_base:%d tx_fifo_size:%08x rx_fifo_size:%08x\n",psc_num,psc_fifo_base[psc_num],tx_fifo_size,rx_fifo_size);
++ /* reset and enable the slices */
++ out_be32(psc + 0x80, 0x80);
++ out_be32(psc + 0x80, 0x01);
++ out_be32(psc + 0xc0, 0x80);
++ out_be32(psc + 0xc0, 0x01);
++
++ iounmap(psc);
++ }
++ }
++}
++static void mpc5125_psc_iopad_init(void __iomem *ioctl, char *name)
++{
++ struct device_node *np;
++ const u32 *cell_index;
++ char *default_psc = "fsl,mpc5125-psc";
++ char *psc_name;
++
++ if (name)
++ psc_name = name;
++ else
++ psc_name = default_psc;
++
++ for_each_compatible_node(np, NULL, psc_name) {
++ cell_index = of_get_property(np, "cell-index", NULL);
++ if (cell_index) {
++ u8 __iomem *pscioctl;
++ int psc_num = *cell_index;
++ if(psc_num>1)continue;
++ pscioctl = ioctl + 0x76+5*psc_num;
++ out_8(pscioctl++, 0x07);
++ out_8(pscioctl++, 0x03);
++ out_8(pscioctl++, 0x03);
++ out_8(pscioctl++, 0x03);
++ out_8(pscioctl++, 0x03);
++ }
++ }
++}
++
++void mpc5121ads_diu_io_pm_restore(void)
++ {
++ struct device_node *np;
++#ifndef CONFIG_MPC5125_TWR
++#define DIU_CLK 0x284
++#define DIU_HSYN 0x288
++#define DIU_IO_OFFSET 0x294
++#define DIU_IO_SIZE 0x68
++#else
++#define DIU_CLK 0x2f
++#define DIU_DE 0x30
++#define DIU_HSYN 0x31
++#define DIU_VSYN 0x32
++#endif
++ /*
++ * io pad config
++ */
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-ioctl");
++ if(!np)
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5125-ioctl");
++ if (np) {
++#ifndef CONFIG_MPC5125_TWR
++ void __iomem *ioctl = of_iomap(np, 0);
++ int i, count = DIU_IO_SIZE / 4;
++ u32 *reg;
++
++ reg = ioctl + DIU_CLK;
++ *reg = 0x107;
++ reg = ioctl + DIU_HSYN;
++ *reg = 0x103;
++ reg = ioctl + DIU_IO_OFFSET;
++ for (i = 0; i < count; i++)
++ *reg++ = 0x103;
++#else
++ u8 __iomem *ioctl = of_iomap(np, 0);
++ out_8(ioctl + DIU_CLK,0x07);
++ out_8( ioctl + DIU_DE,0x03);
++ out_8(ioctl + DIU_HSYN,0x03);
++ out_8(ioctl + DIU_VSYN,0x03);
++
++#endif
++ mpc5125_psc_iopad_init(ioctl, "fsl,mpc5125-psc-ac97");
++
++ of_node_put(np);
++ iounmap(ioctl);
++ }
++}
++
++EXPORT_SYMBOL(mpc5121ads_diu_io_pm_restore);
++
++void mpc5121ads_ac97_pm_restore(void)
++{
++ struct device_node *np;
++
++ /*
++ * io pad config
++ */
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5125-ioctl");
++ if (np) {
++ void __iomem *ioctl = of_iomap(np, 0);
++
++ mpc5125_psc_iopad_init(ioctl, "fsl,mpc5125-psc-ac97");
++
++ of_node_put(np);
++ iounmap(ioctl);
++ }
++
++ mpc5125_psc_fifo_init("fsl,mpc5125-psc-ac97");
++}
++EXPORT_SYMBOL(mpc5121ads_ac97_pm_restore);
++#if CONFIG_PPC_MPC5125
++static void mpc5125_can_io_controller_init(void)
++{
++ /*can1_tx psc9 pin 0*/
++ /*mpc5125_psc_io_controller_set(9, 0, 0x03);*/
++ /*can2_tx psc9 pin 1*/
++ /*mpc5125_psc_io_controller_set(9, 1, 0xc3);*/
++}
++#endif
++static void __init mpc5125_board_setup(void)
++{
++ struct device_node *np;
++ void __iomem *i2cctl;
++
++ /*
++ * io pad config
++ */
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5125-ioctl");
++ if (np) {
++ void __iomem *ioctl = of_iomap(np, 0);
++
++ mpc5125_psc_iopad_init(ioctl, NULL);
++ /*mpc5121_can_iopad_init(ioctl);*/
++
++ of_node_put(np);
++ iounmap(ioctl);
++ }
++ mpc5125_psc_fifo_init(NULL);
++}
++/*
++ isusb:0 init as fec2
++ isusb:1 init as usb
++*/
++void mpc5125_fec2_usb_io_init(unsigned char isusb)
++{
++ unsigned int offset[]={0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,
++ 0x6b,0x6c,0x6d,0x6e
++ };
++ unsigned char usb_init[]={0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
++ 0x03,0x03,0x03,0x03
++ };
++ unsigned char fec2_init[]={ 0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,
++ 0x43,0x43,0x43,0x43
++ };
++ unsigned int i;
++ for(i=0;i<sizeof(offset)/sizeof(offset[0]);i++)
++ {
++ mpc5125_io_controller_set(offset[i],(isusb)?usb_init[i]:fec2_init[i]);
++ }
++}
++EXPORT_SYMBOL(mpc5125_fec2_usb_io_init);
++extern int __init ads5121_pm_init(void);
++static void __init mpc5125_ads_setup_arch(void)
++{
++ printk(KERN_INFO "MPC5125 ADS board from Freescale Semiconductor\n");
++
++ preallocate_diu_videomemory();
++ mpc5125_board_setup();
++#if CONFIG_PPC_MPC5125
++ mpc5125_can_io_controller_init();
++#endif
++
++#ifdef CONFIG_PM
++#ifdef CONFIG_MPC5121_ADS_HIB
++ ads5121_pm_init();
++#else
++ mpc512x_pm_init();
++#endif
++#endif
++
++}
++
++static struct of_device_id __initdata of_bus_ids[] = {
++ { .name = "soc", },
++ { .name = "localbus", },
++ { .compatible = "fsl,mpc5125-nfc", },
++ {},
++};
++
++static void __init mpc5125_ads_declare_of_platform_devices(void)
++{
++ if (of_platform_bus_probe(NULL, of_bus_ids, NULL))
++ printk(KERN_ERR __FILE__ ": "
++ "Error while probing of_platform bus\n");
++}
++
++static void __init mpc5125_ads_init_IRQ(void)
++{
++ struct device_node *np;
++
++ np = of_find_compatible_node(NULL, NULL, "fsl,ipic");
++ if (!np)
++ return;
++
++ ipic_init(np, 0);
++ of_node_put(np);
++
++ /*
++ * Initialize the default interrupt mapping priorities,
++ * in case the boot rom changed something on us.
++ */
++ ipic_set_default_priority();
++}
++
++/*
++ * Called very early, MMU is off, device-tree isn't unflattened
++ */
++static int __init mpc5125_ads_probe(void)
++{
++ unsigned long root = of_get_flat_dt_root();
++
++ return of_flat_dt_is_compatible(root, "fsl,mpc5125ads");
++}
++
++define_machine(mpc5125_ads) {
++ .name = "MPC5125 ADS",
++ .probe = mpc5125_ads_probe,
++ .setup_arch = mpc5125_ads_setup_arch,
++ .init = mpc5125_ads_declare_of_platform_devices,
++ .init_IRQ = mpc5125_ads_init_IRQ,
++ .get_irq = ipic_get_irq,
++ .calibrate_decr = generic_calibrate_decr,
++};
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/mpc512x_pm.c linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc512x_pm.c
+--- linux-2.6.29/arch/powerpc/platforms/512x/mpc512x_pm.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc512x_pm.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,602 @@
++/*
++ * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * Description:
++ * This file contains power management code for MPC5121eADS
++ *
++ * This file is part of the Linux kernel
++ *
++ * This is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/suspend.h>
++#include <linux/of_platform.h>
++#include <asm/time.h>
++#include <asm/mpc512x.h>
++#include <asm/ipic.h>
++#include <asm/reg.h>
++#include <sysdev/fsl_soc.h>
++
++#include "mpc512x_pm.h"
++
++#include <linux/delay.h>
++
++
++struct mpc512x_pm mpc512x_pm_data;
++static u32 mpc512x_targeted_state = MPC512x_PM_NONE;
++
++/*
++ * Name : mpc512x_clrevents
++ * Desc : This function clears the GPIo events and the CAN events
++ *
++ * Parameters : void
++ * Return : void
++ */
++void mpc512x_clrevents(struct mpc512x_pm *p_pmdata)
++{
++
++ u32 *gpio, reg;
++ u8 *mscan = NULL;
++
++ gpio = (u32 *)((u32)p_pmdata->mbar + MPC512x_IMMRBAR_GPIO_OFFSET);
++ mscan = (u8 *)((u32)p_pmdata->mbar + MPC512x_IMMRBAR_MSCAN_OFFSET);
++
++ reg = in_be32(&gpio[MPC512x_GPIO_GPIER >> 2]);
++ out_be32(&gpio[MPC512x_GPIO_GPIER >> 2], reg);
++}
++
++/*
++ * Name : mpc512x_pm_setup
++ * Desc : This function is called to setup and map the IO region.
++ *
++ * Parameters : struct mpc512x_pm *p_pmdata
++ * Return : void
++ */
++int mpc512x_pm_setup(struct mpc512x_pm *p_pmdata)
++{
++ memset(p_pmdata, 0, sizeof(struct mpc512x_pm));
++
++ p_pmdata->mbar = ioremap(get_immrbase(), MPC512x_IMMRBAR_MEM_MAPPED);
++ if (!p_pmdata->mbar) {
++ printk(KERN_ERR "Error mapping MBAR registers\n");
++ return -1;
++ }
++#ifdef CONFIG_MPC5121_PM_TEST
++ mpc512x_pm_test_setup();
++#endif
++ return 0;
++}
++
++/*
++ * Name : mpc512x_pm_release
++ * Desc : This is called to unmap/release the allocated resources.
++ *
++ * Parameters : void
++ * Return : void
++ */
++void mpc512x_pm_release(struct mpc512x_pm *p_pmdata)
++{
++ unsigned long flags;
++ if (!p_pmdata->mbar)
++ return;
++ local_irq_save(flags);
++ iounmap(p_pmdata->mbar);
++ memset(p_pmdata, 0, sizeof(struct mpc512x_pm));
++ local_irq_restore(flags);
++}
++
++/*
++ * Name : mpc512x_sleep
++ * Desc : This function is called to enter the Sleep mode by setting the
++ * [SLEEP] bit in HID0 and [POW] bit in MSR.
++ *
++ * Parameters : void
++ * Return : void
++ */
++static void mpc512x_sleep(void)
++{
++ u32 hid0, msr;
++
++ /* Enable SLEEP mode and disable the rest */
++ hid0 = mfspr(SPRN_HID0);
++ mtspr(SPRN_HID0, (hid0 & ~(HID0_DOZE | HID0_NAP
++ | HID0_DPM)) | HID0_SLEEP);
++ asm volatile("isync" : : : "memory");
++ asm volatile("sync" : : : "memory");
++
++ msr = mfmsr();
++ mtmsr(msr | MSR_EE);
++ asm volatile("isync" : : : "memory");
++ asm volatile("sync" : : : "memory");
++
++ /* Enter Sleep mode*/
++ msr = mfmsr();
++ mtmsr(msr | MSR_POW);
++ asm volatile("isync" : : : "memory");
++ asm volatile("sync" : : : "memory");
++
++ msr = mfmsr();
++ mtmsr(msr & ~MSR_EE);
++ asm volatile("isync" : : : "memory");
++ asm volatile("sync" : : : "memory");
++
++ /* Disable sleep modes */
++ hid0 = mfspr(SPRN_HID0);
++ mtspr(SPRN_HID0, (hid0 & ~(HID0_DOZE | HID0_NAP | HID0_SLEEP)));
++ asm volatile("isync" : : : "memory");
++ asm volatile("sync" : : : "memory");
++}
++/*
++ * Name : mpc512x_pmc_clrevent
++ * Desc : This function needs to be called by the interrupt handlers of
++ * the wakeup sources. This is needed since a PMC interrupt is
++ * not guaranteed on MPC5121 v1.0, while an interrupt from the
++ * wakeup source (GPIO / CAN) is.
++ *
++ * Parameters : void
++ * Return : void
++ */
++void mpc512x_pmc_clrevent(void)
++{
++ struct mpc512x_pmc *pmc;
++
++ if(mpc512x_pm_data.mbar){
++ pmc = (struct mpc512x_pmc *)((u32)mpc512x_pm_data.mbar +
++ MPC512x_IMMRBAR_PMC_OFFSET);
++ if(in_be32(&pmc->pmc_er)& 0x1){
++ out_be32(&pmc->pmc_er, 0x1);
++ }
++ out_be32(&pmc->pmc_er, 0x7);
++ }
++}
++EXPORT_SYMBOL_GPL(mpc512x_pmc_clrevent);
++
++/*
++ * Name : mpc512x_set_gpio_wakeup
++ * Desc : This function would initialise the gpio with the given detection mode
++ * and enable the interrupt.
++ *
++ * Parameters :
++ * Return : int
++ */
++int mpc512x_set_gpio_wakeup(unsigned int gpio_num, unsigned int detect_mode)
++{
++ volatile u32 reg;
++ u32 __iomem *gpio;
++
++ gpio = ioremap((u32)get_immrbase() + MPC512x_IMMRBAR_GPIO_OFFSET,
++ MPC512x_GPIO_MEM_MAP);
++ if (!gpio) {
++ printk("GPIO memory could not be mapped. \n");
++ return -1;
++ }
++ gpio_num = 31 - gpio_num;
++ reg = in_be32(&gpio[MPC512x_GPIO_IMR >> 2]);
++ reg |= 1 << gpio_num;
++ out_be32(&gpio[MPC512x_GPIO_IMR >> 2], reg);
++
++ reg = in_be32(&gpio[MPC512x_GPIO_ICR1 >> 2]);
++ reg &= ~(0x3 << (gpio_num * 2));
++ reg |= ((detect_mode & 3)<< (gpio_num * 2));
++ out_be32(&gpio[MPC512x_GPIO_ICR1 >> 2], reg);
++
++ iounmap(gpio);
++ return 0;
++}
++
++EXPORT_SYMBOL_GPL(mpc512x_set_gpio_wakeup);
++
++/*
++ * Name : mpc512x_pm_valid
++ * Desc : Checks whether the PM state is valid
++ *
++ * Parameters : void
++ * Return : 1 - Valid , 0 - Invalid
++ */
++static int mpc512x_pm_valid(suspend_state_t state)
++{
++ switch(state){
++ case PM_SUSPEND_STANDBY:
++ case PM_SUSPEND_MEM:
++ return 1;
++ default:
++ return 0;
++ }
++}
++
++/*
++ * Name : mpc512x_pm_settarget
++ * Desc : Set the state to which the system is to enter.
++ *
++ * Parameters : void
++ * Return : 0 - Success
++ */
++static int mpc512x_pm_settarget(suspend_state_t state)
++{
++ switch(state){
++ case PM_SUSPEND_STANDBY:
++ mpc512x_targeted_state = MPC512x_PM_STANDBY;
++ break;
++ case PM_SUSPEND_MEM:
++ mpc512x_targeted_state = MPC512x_PM_SUSP_MEM;
++ break;
++ default:
++ mpc512x_targeted_state = MPC512x_PM_NONE;
++ }
++ return 0;
++}
++
++/*
++ * Name : mpc512x_set_ipic_regs
++ * Desc : Save the IPIC Mask registers and enable the wakeup interrupts
++ *
++ * Parameters : void
++ * Return : void
++ */
++static void mpc512x_set_ipic_regs(struct mpc512x_pm *p_pmdata)
++{
++ u32 *ipic = (u32 *)((u32)p_pmdata->mbar +
++ MPC512x_IMMRBAR_IPIC_OFFSET);
++
++ /* Save the current IPIC mask register values. */
++ p_pmdata->ipic_simsr_h = in_be32(&ipic[IPIC_SIMSR_H >> 2]);
++ p_pmdata->ipic_simsr_l = in_be32(&ipic[IPIC_SIMSR_L >> 2]);
++
++ /* Disable all the interrupts except the wakeup sources */
++ out_be32(&ipic[IPIC_SIMSR_H >> 2], MPC512x_IPIC_MSRH_MSCAN1
++ | MPC512x_IPIC_MSRH_MSCAN2);
++ out_be32(&ipic[IPIC_SIMSR_L >> 2], MPC512x_IPIC_MSRL_RTCSEC |
++ MPC512x_IPIC_MSRL_PMC | MPC512x_IPIC_MSRL_GPIO);
++}
++
++/*
++ * Name : mpc512x_restore_ipic_regs
++ * Desc : Restore the IPIC Mask registers to original values.
++ *
++ * Parameters : void
++ * Return : void
++ */
++static void mpc512x_restore_ipic_regs(struct mpc512x_pm *p_pmdata)
++{
++ u32 *ipic = (u32 *)((u32)p_pmdata->mbar +
++ MPC512x_IMMRBAR_IPIC_OFFSET);
++ /* Restore the IPIC masks to saved values */
++ out_be32(&ipic[IPIC_SIMSR_L >> 2], p_pmdata->ipic_simsr_l );
++ out_be32(&ipic[IPIC_SIMSR_H >> 2], p_pmdata->ipic_simsr_h);
++}
++/*
++ * Name : mpc512x_set_rtc_wakeup
++ * Desc : This Function would set up the Wake-Up source configurations
++ * in the RTC registers. The RTC interrupts would be generated for GPIO[28-31]
++ * and CAN 1 & 2 receive Interrupts.
++ *
++ * Parameters : void
++ * Return : void
++ */
++static void mpc512x_set_rtc_wakeup(struct mpc512x_pm *p_pmdata)
++{
++ u32 rtc_reg;
++ u32 *rtc;
++ u32 alm_hr, alm_min, cur_hr, cur_min;
++ int offset_minutes;
++
++ if (!p_pmdata->mbar)
++ return;
++
++ rtc = (u32 *)((u32)p_pmdata->mbar + MPC512x_IMMRBAR_RTC_OFFSET);
++
++ rtc_reg = in_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2]);
++ p_pmdata->rtc_keepalive = rtc_reg;
++
++ /* Set the Active LVL values for the Wake-up Sources[1-5] */
++ rtc_reg |= MPC512x_RTCKAR_WKUP_SRCLVL;
++ out_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2], rtc_reg);
++
++ /* Enable the Wake-Up sources and disable Hibernate mode. */
++ rtc_reg |= (MPC512x_RTCKAR_WKUP_SRCEN | MPC512x_RTCKAR_DIS_HIBMODE);
++ out_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2], rtc_reg);
++
++ /* Set the Target Time Register to a Future Value */
++ p_pmdata->rtc_targettime = in_be32(&rtc[MPC512x_RTC_TTR >> 2]);
++
++ rtc_reg = in_be32(&rtc[MPC512x_RTC_AIER >> 2]);
++
++ if (rtc_reg & MPC512x_RTCAIER_ALMEN_MASK) {
++ /*Alarm was set.. Let us wakeup in that time..*/
++ alm_hr = (rtc_reg >> MPC512x_RTC_HR_OFFSET)
++ & MPC512x_RTC_HR_MASK;
++ alm_min = (rtc_reg >> MPC512x_RTC_MIN_OFFSET)
++ & MPC512x_RTC_MIN_MASK;
++ rtc_reg = in_be32(&rtc[MPC512x_RTC_CTR >> 2]);
++ cur_min = (rtc_reg >> MPC512x_RTC_MIN_OFFSET)
++ & MPC512x_RTC_MIN_MASK;
++
++ if (in_be32(&rtc[MPC512x_RTC_TSR >> 2])
++ & MPC512x_RTCTSR_SLCHR_MASK) {
++ /* 12 Hour Format*/
++ cur_hr = (rtc_reg >> MPC512x_RTC_HR_OFFSET) & 0xF;
++ if (rtc_reg & MPC512x_RTC_CTR_PM)
++ cur_hr += 12;
++ } else
++ cur_hr = (rtc_reg >> MPC512x_RTC_HR_OFFSET)
++ & MPC512x_RTC_HR_MASK;
++ offset_minutes = (alm_hr * MPC512x_RTC_MINS_PER_HR + alm_min) -
++ (cur_hr * MPC512x_RTC_MINS_PER_HR + cur_min);
++
++ if (offset_minutes > 0) {
++ out_be32(&rtc[MPC512x_RTC_TTR >> 2],
++ in_be32(&rtc[MPC512x_RTC_ATR >> 2]) +
++ (offset_minutes * MPC512x_RTC_MINS_PER_HR));
++ } else
++ out_be32(&rtc[MPC512x_RTC_TTR >> 2],
++ MPC512x_RTCTTR_MAXTIMEOUT);
++ } else
++ out_be32(&rtc[MPC512x_RTC_TTR >> 2], MPC512x_RTCTTR_MAXTIMEOUT);
++
++}
++
++static void mpc512x_restore_rtc_regs(struct mpc512x_pm *p_pmdata)
++{
++ u32 *rtc;
++
++ if (!p_pmdata->mbar)
++ return;
++
++ rtc = (u32 *)((u32)p_pmdata->mbar + MPC512x_IMMRBAR_RTC_OFFSET);
++
++ /* Restore the RTC Registers */
++ out_be32(&rtc[MPC512x_RTC_KEEPALIVE >> 2],
++ p_pmdata->rtc_keepalive);
++ out_be32(&rtc[MPC512x_RTC_TTR >> 2], p_pmdata->rtc_targettime);
++}
++
++/*
++ * Name : mpc512x_set_ddr_selfrefresh
++ * Desc : Set the DDRC SELFREFRESH registers, to enter and exit
++ * DDR Self Refresh mode on entering Deep Sleep mode.
++ *
++ * Parameters : void
++ * Return : void
++ */
++static void mpc512x_set_ddr_selfrefresh(struct mpc512x_pm *p_pmdata)
++{
++ struct ddr512x *ddrc;
++
++ if (!p_pmdata->mbar)
++ return;
++
++ ddrc = (struct ddr512x *)((u32)p_pmdata->mbar +
++ MPC512x_IMMRBAR_DDRC_OFFSET);
++
++ p_pmdata->ddrc_sysconfig = in_be32(&ddrc->ddr_sys_config);
++
++ /* Write the register contents with SELF-REFRESH EN bit set.*/
++ out_be32(&ddrc->ddr_sys_config, p_pmdata->ddrc_sysconfig
++ | MPC512x_DDRC_SELFREFEN);
++
++ /* Set the Self Refresh Entry Commands */
++ out_be16(&ddrc->self_refresh_cmd_0, MPC512x_DDRC_SELF_REF_CMD0);
++ out_be16(&ddrc->self_refresh_cmd_1, MPC512x_DDRC_SELF_REF_CMD1);
++ out_be16(&ddrc->self_refresh_cmd_2, MPC512x_DDRC_SELF_REF_CMD2);
++ out_be16(&ddrc->self_refresh_cmd_3, MPC512x_DDRC_SELF_REF_CMD3);
++
++ /* Set the Self Refresh Exit Commands */
++ out_be16(&ddrc->self_refresh_cmd_4, MPC512x_DDRC_SELF_REF_CMD4);
++ out_be16(&ddrc->self_refresh_cmd_5, MPC512x_DDRC_SELF_REF_CMD5);
++ out_be16(&ddrc->self_refresh_cmd_6, MPC512x_DDRC_SELF_REF_CMD6);
++ out_be16(&ddrc->self_refresh_cmd_7, MPC512x_DDRC_SELF_REF_CMD7);
++}
++
++static void mpc512x_restore_ddr_regs(struct mpc512x_pm *p_pmdata)
++{
++ struct ddr512x *ddrc;
++
++ if (!p_pmdata->mbar)
++ return;
++
++ ddrc = (struct ddr512x *)((u32)p_pmdata->mbar +
++ MPC512x_IMMRBAR_DDRC_OFFSET);
++ out_be32(&ddrc->ddr_sys_config, p_pmdata->ddrc_sysconfig);
++}
++
++void mpc512x_prepare_deepsleep(struct mpc512x_pm *p_pmdata)
++{
++ mpc512x_set_ddr_selfrefresh(p_pmdata);
++
++ /*
++ * Enable the wakeup sources and set RTC Target Time
++ * to future
++ */
++ mpc512x_set_rtc_wakeup(p_pmdata);
++
++#ifdef CONFIG_PPC_MPC5125
++ struct mpc512x_pmc *pmc;
++ pmc = (struct mpc512x_pmc *)((u32)p_pmdata->mbar +
++ MPC512x_IMMRBAR_PMC_OFFSET);
++ out_be32(&pmc->pmc_wse,0xff);
++ out_be32(&pmc->pmc_wsp,0x00);
++ mpc512x_set_gpio_wakeup(0, 3);
++#endif
++// mpc512x_set_gpio_wakeup(31, 3);
++}
++
++void mpc512x_finish_deepsleep(struct mpc512x_pm *p_pmdata)
++{
++ /* Restore the DDR and RTC registers on wake-up.*/
++ mpc512x_restore_ddr_regs(p_pmdata);
++ mpc512x_restore_rtc_regs(p_pmdata);
++
++}
++
++/*
++ * Name : mpc512x_pm_prepare
++ * Desc : This function would map the IO regions. Also sets the DDRC and
++ * RTC regs for Deep Sleep Mode.
++ *
++ * Parameters : void
++ * Return : int
++ * ENOSYS
++ *
++ */
++static int mpc512x_pm_prepare(void)
++{
++ mpc512x_pm_setup(&mpc512x_pm_data);
++
++ switch(mpc512x_targeted_state) {
++ case MPC512x_PM_STANDBY:
++ mpc512x_prepare_deepsleep(&mpc512x_pm_data);
++ break;
++ case MPC512x_PM_SUSP_MEM:
++ mpc512x_prepare_deepsleep(&mpc512x_pm_data);
++ break;
++ }
++ return 0;
++}
++
++/*
++ * Name : mpc512x_enter_deepsleep
++ * Desc : This function puts the MPC5121e system to Deep-Sleep State. The
++ * Core is first put to sleep. After this the H/W sequencers take
++ * the system to Deep-Sleep. Before entering the Deep-
++ * Sleep state the Wake-Up sources are set for GPIO[28-31] and CAN
++ * 1 & 2 receiver interrupts.
++ *
++ * Parameters : void
++ * Return : int
++ *
++ */
++int mpc512x_enter_deepsleep(struct mpc512x_pm *p_pmdata)
++{
++ struct mpc512x_pmc *pmc;
++ /* Enable the GPIO and CAN Interrupts */
++ mpc512x_set_ipic_regs(p_pmdata);
++
++ /* Don't let DEC expire any time soon */
++ mtspr(SPRN_DEC, MPC512x_DEC_MAXTIMEOUT);
++
++ pmc = (struct mpc512x_pmc *)((u32)p_pmdata->mbar +
++ MPC512x_IMMRBAR_PMC_OFFSET);
++ /* Set the DSM, DDROFF & COREOFF bits in PMC CR register.*/
++ out_be32(&pmc->pmc_cr, MPC512x_PMCCR_DSMEN | MPC512x_PMCCR_DDROFF
++ | MPC512x_PMCCR_COREOFF);
++ out_be32(&pmc->pmc_mr, MPC512x_PMCMR_PMCIE);
++
++#ifdef CONFIG_PPC_MPC5125
++ out_be32(&pmc->pmc_wse, 0x48);
++ out_be32(&pmc->pmc_wsp, 0x40);
++#endif
++
++ /* Replace the Exception handler at 0x500 with our custom
++ * handler to clear the PMC bit.
++ */
++ mpc5121_copy_pmcclr();
++
++ /* Put core to SLEEP so that MPC512x enters Deep-Sleep.*/
++ mpc512x_sleep();
++
++ /* Restore the Original exception handler at 0x500 */
++ mpc5121_reinstall_handler();
++
++ /* We are out of Deep Sleep.. Lets restart jiffies */
++ wakeup_decrementer();
++
++ /* clearing the events of wake-up for GPIO and CAN */
++ mpc512x_clrevents(p_pmdata);
++
++ /* Reset the PMC CR register. */
++ out_be32(&pmc->pmc_cr, 0x0);
++ out_be32(&pmc->pmc_mr, 0x0);
++
++ /* Restore the IPIC regs to their original values */
++ mpc512x_restore_ipic_regs(p_pmdata);
++ return 0;
++}
++
++/*
++ * Name : mpc512x_pm_enter
++ * Desc : This function is exported to the Power Management Core. This
++ * ` function is called with the state which the system should enter.
++ *
++ * Parameters : state - PM_SUSPEND_STANDBY
++ - PM_SUSPEND_MEM
++ * Return : int
++ * -1 : FAILED
++ * 0 : SUCCESS
++ */
++static int mpc512x_pm_enter(suspend_state_t state)
++{
++ if (!mpc512x_pm_data.mbar)
++ {
++ printk(KERN_ERR "Failed to enter PM mode as IO not mapped.\n");
++ return -1;
++ }
++
++ switch(mpc512x_targeted_state){
++ case MPC512x_PM_STANDBY:
++ mpc512x_enter_deepsleep(&mpc512x_pm_data);
++ break;
++ case MPC512x_PM_SUSP_MEM:
++ printk(KERN_ERR "Suspend to RAM not implemented\n");
++ mpc512x_enter_deepsleep(&mpc512x_pm_data);
++ default:
++ break;
++ }
++ return 0;
++}
++
++/*
++ * Name : mpc512x_pm_finish
++ * Desc : This routine is called by the kernel on exit from
++ * power down modes. Restores the DDRC and RTC regs
++ * suspend to memory. Also releases allocated resources.
++ *
++ * Parameters : void
++ * Return : void
++ */
++static void mpc512x_pm_finish(void)
++{
++ switch(mpc512x_targeted_state){
++ case MPC512x_PM_STANDBY:
++ mpc512x_finish_deepsleep(&mpc512x_pm_data);
++ break;
++ case MPC512x_PM_SUSP_MEM:
++ mpc512x_finish_deepsleep(&mpc512x_pm_data);
++ break;
++ }
++ mpc512x_targeted_state = MPC512x_PM_NONE;
++
++ mpc512x_pm_release(&mpc512x_pm_data);
++}
++
++static struct platform_suspend_ops mpc512x_pm_ops = {
++ .valid = mpc512x_pm_valid,
++ .begin = mpc512x_pm_settarget,
++ .prepare = mpc512x_pm_prepare,
++ .enter = mpc512x_pm_enter,
++ .finish = mpc512x_pm_finish,
++};
++#ifndef CONFIG_MPC5121_ADS_HIB
++int fsl_deep_sleep(void)
++{
++ return mpc512x_targeted_state;
++}
++#endif
++/*
++ * Name : mpc512x_pm_init
++ * Desc : This function registers the platform_suspend_ops
++ * structure with the kernel.
++ *
++ * Parameters : void
++ * Return : int
++ */
++int __init mpc512x_pm_init(void)
++{
++ suspend_set_ops(&mpc512x_pm_ops);
++ return 0;
++}
++
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/mpc512x_pm.h linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc512x_pm.h
+--- linux-2.6.29/arch/powerpc/platforms/512x/mpc512x_pm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc512x_pm.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,159 @@
++/*
++ * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * Description:
++ * This file power management code for MPC5121eADS
++ *
++ * This file is part of the Linux kernel
++ *
++ * This is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++
++#ifndef __MPC512x_PM_H__
++#define __MPC512x_PM_H__
++
++/* Peripheral address offsets from IMMRBAR */
++#define MPC512x_IMMRBAR_RTC_OFFSET 0xA00
++#define MPC512x_IMMRBAR_IPIC_OFFSET 0xC00
++#define MPC512x_IMMRBAR_PMC_OFFSET 0x1000
++#define MPC512x_IMMRBAR_GPIO_OFFSET 0x1100
++#define MPC512x_IMMRBAR_DDRC_OFFSET 0x9000
++#define MPC512x_IMMRBAR_CLK_OFFSET 0x00F00
++#define MPC512x_IMMRBAR_GPT_OFFSET 0x00B00
++#define MPC512x_IMMRBAR_FEC_OFFSET 0x02800
++#define MPC512x_IMMRBAR_SRAM_OFFSET 0x000C4
++#define MPC512x_IMMRBAR_MSCAN_OFFSET 0x01300
++
++/* Memory mapped by Power management module */
++#define MPC512x_IMMRBAR_MEM_MAPPED 0x10000
++#define MPC512x_GPIO_MEM_MAP 0x100
++
++/* Register offsets for RTC */
++#define MPC512x_RTC_TSR 0x00
++#define MPC512x_RTC_AIER 0x0C
++#define MPC512x_RTC_CTR 0x10
++#define MPC512x_RTC_TTR 0x20
++#define MPC512x_RTC_ATR 0x24
++#define MPC512x_RTC_KEEPALIVE 0x28
++
++/* RTC bit positions and masks*/
++#define MPC512x_RTCTSR_SLCHR_MASK (1 << 21)
++#define MPC512x_RTCAIER_ALMEN_MASK (1 << 24)
++#define MPC512x_RTC_CTR_PM (1 << 20)
++#define MPC512x_RTC_HR_OFFSET 16
++#define MPC512x_RTC_HR_MASK 0x1F
++#define MPC512x_RTC_MIN_OFFSET 8
++#define MPC512x_RTC_MIN_MASK 0x3F
++#define MPC512x_RTC_MINS_PER_HR 60
++
++/* Register offsets for GPIO */
++#define MPC512x_GPIO_IMR 0x10
++#define MPC512x_GPIO_ICR1 0x14
++#define MPC512x_GPIO_ICR2 0x18
++#define MPC512x_GPIO_GPIER 0x0C
++
++/* Register offsets for MSCAN */
++#define MPC512x_MSCAN_CANRFLG 0x08
++#define MPC512x_MSCAN_CANRIER 0x09
++
++/* Bit positions in IPIC memory region */
++#define MPC512x_IPIC_MSRH_MSCAN1 (1 << 4)
++#define MPC512x_IPIC_MSRH_MSCAN2 (1 << 3)
++
++#define MPC512x_IPIC_MSRL_GPIO (1 << 17)
++#define MPC512x_IPIC_MSRL_RTCSEC (1 << 16)
++#define MPC512x_IPIC_MSRL_RTCALRM (1 << 15)
++#define MPC512x_IPIC_MSRL_PMC (1 << 12)
++
++/* Bit positions in PMC memory region */
++#define MPC512x_PMCCR_DSMEN (1 << 2)
++#define MPC512x_PMCCR_DDROFF (1 << 1)
++#define MPC512x_PMCCR_COREOFF (1 << 0)
++#define MPC512x_PMCMR_PMCIE (1 << 0)
++
++/* Bit positions in DDRC memory region */
++#define MPC512x_DDRC_SELFREFEN (1 << 18)
++
++/* DDRC commands to set the DRAM in and out of Self Refresh */
++/* These commands have worked on the MPC5121ADS board */
++#define MPC512x_DDRC_SELF_REF_CMD0 0x3C00
++#define MPC512x_DDRC_SELF_REF_CMD1 0x4420
++#define MPC512x_DDRC_SELF_REF_CMD2 0x4210
++#define MPC512x_DDRC_SELF_REF_CMD3 0x1410
++
++#define MPC512x_DDRC_SELF_REF_CMD4 0x1C00
++#define MPC512x_DDRC_SELF_REF_CMD5 0x3C08
++#define MPC512x_DDRC_SELF_REF_CMD6 0x4200
++#define MPC512x_DDRC_SELF_REF_CMD7 0x3800
++
++/* RTC Keep alive register values*/
++#define MPC512x_RTCKAR_WKUP_SRCLVL 0x001C0000
++#define MPC512x_RTCKAR_WKUP_SRCEN 0x1F000000
++#define MPC512x_RTCKAR_DIS_HIBMODE 0x00000080
++
++/* RTC Target Time register Timeout*/
++#define MPC512x_RTCTTR_MAXTIMEOUT 0xFFFFFFFF
++
++/* Decrementer timeout */
++#define MPC512x_DEC_MAXTIMEOUT 0x7FFFFFFF
++
++/* Power Management states */
++#define MPC512x_PM_NONE 0
++#define MPC512x_PM_STANDBY 1
++#define MPC512x_PM_SUSP_MEM 2
++
++/* PMC registers*/
++struct mpc512x_pmc {
++ u32 pmc_cr; /* Configuration register - 0x00 */
++ u32 pmc_er; /* Event register - 0x04 */
++ u32 pmc_mr; /* Mask register - 0x08 */
++ u32 pmc_sr; /* Shadow register - 0x0C */
++#ifdef CONFIG_PPC_MPC5125
++ u32 pmc_wse; /*MPC5125 PMC wakeup source register -0x10*/
++ u32 pmc_wsp; /*MPC5125 PMC wakeup source polarity register -0x14*/
++#endif
++};
++
++/* Data structure used by the Power management module */
++struct mpc512x_pm{
++
++ /* Pointer to IMMRBAR (ioremaped) */
++ void __iomem *mbar;
++
++ /* Registers saved/restored by PM module */
++ u32 ipic_simsr_l;
++ u32 ipic_simsr_h;
++ u32 rtc_keepalive;
++ u32 rtc_targettime;
++ u32 ddrc_sysconfig;
++};
++
++/* Structure members used to store the resister contents
++ * for peripherals which cdont have a driver to restore.
++ */
++struct ads5121_hib_regs{
++ u32 ipic_regs[30];
++ u32 clk_regs[22];
++ u32 gpt_regs[32];
++ u32 gpio_regs[7];
++ u32 fec_regs[512];
++};
++
++int mpc512x_pm_setup(struct mpc512x_pm *p_pmdata);
++void mpc512x_pm_release(struct mpc512x_pm *p_pmdata);
++void mpc512x_prepare_deepsleep(struct mpc512x_pm *p_pmdata);
++int mpc512x_enter_deepsleep(struct mpc512x_pm *p_pmdata);
++void mpc512x_finish_deepsleep(struct mpc512x_pm *p_pmdata);
++
++extern void mpc5121_copy_pmcclr(void);
++extern void mpc5121_reinstall_handler(void);
++
++#ifdef CONFIG_MPC5121_PM_TEST
++extern void mpc512x_pm_test_setup(void);
++#endif
++
++#endif /* __MPC512x_PM_H__ */
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/mpc512x_pm_test.c linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc512x_pm_test.c
+--- linux-2.6.29/arch/powerpc/platforms/512x/mpc512x_pm_test.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc512x_pm_test.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,192 @@
++/*
++ * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * Description:
++ * This file contains lowlevel PM test code
++ *
++ * This file is part of the Linux kernel
++ *
++ * This is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ */
++#include <linux/interrupt.h>
++#include <linux/of_platform.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++#include <asm/time.h>
++#include <asm/reg.h>
++#include <sysdev/fsl_soc.h>
++
++#define DEBUG
++
++u8 *xmscan = NULL;
++u32 *xgpio = NULL;
++u32 once = 0;
++u32 irq;
++
++extern int mpc512x_set_gpio_wakeup(unsigned int gpio_num,
++ unsigned int detect_mode);
++extern void mpc512x_pmc_clrevent(void);
++
++static irqreturn_t mpc51xx_gpio_handler(int irq, void *dev_id)
++{
++ mpc512x_pmc_clrevent();
++ if (xgpio) {
++ out_be32((u32 *) ((u32) xgpio + 0x0C), 0xFFFFFFFF);
++#ifdef DEBUG
++ printk( " :)\n");
++#endif
++ }
++ return IRQ_HANDLED;
++}
++static irqreturn_t mpc51xx_can0_handler(int irq, void *dev_id)
++{
++ u8 *mscan = xmscan;
++ mpc512x_pmc_clrevent();
++
++ if (mscan)
++ out_8(mscan + 8, in_8(mscan + 8));
++
++#ifdef DEBUG
++ printk("c0 \n");
++#endif
++
++ return IRQ_HANDLED;
++}
++#ifndef CONFIG_MPC5125_TWR
++static irqreturn_t mpc51xx_can1_handler(int irq, void *dev_id)
++{
++ u8 *mscan = xmscan + 0x80;
++ mpc512x_pmc_clrevent();
++
++ if (mscan)
++ out_8(mscan + 8, in_8(mscan + 8));
++
++#ifdef DEBUG
++ printk("c1 \n");
++#endif
++ return IRQ_HANDLED;
++}
++
++void mpc512x_can_setup(u8 * addr)
++{
++ u32 reg = 0;
++
++ u8 *mscan = addr;
++
++ /* Enable the CAN Module */
++ reg = in_8(mscan + 0x01);
++ reg |= 0x80; //Assert CANE
++ reg &= ~0x10; //Deassert LISTEN
++ out_8(mscan + 1, reg);
++
++ reg = in_8(mscan);
++ reg |= 0x2; //Sleep Req
++ out_8(mscan, reg);
++ mdelay(20);
++ reg = in_8(mscan);
++ reg |= 0x1; //Init req
++ out_8(mscan, reg);
++
++#define MSCAN_CANIDMR0_OFFSET 0x28 /* Identifier Mask Registers */
++#define MSCAN_CANIDMR1_OFFSET 0x29 /* Identifier Mask Registers */
++#define MSCAN_CANIDMR2_OFFSET 0x2C /* Identifier Mask Registers */
++#define MSCAN_CANIDMR3_OFFSET 0x2D /* Identifier Mask Registers */
++#define MSCAN_CANIDMR4_OFFSET 0x38 /* Identifier Mask Registers */
++#define MSCAN_CANIDMR5_OFFSET 0x39 /* Identifier Mask Registers */
++#define MSCAN_CANIDMR6_OFFSET 0x3C /* Identifier Mask Registers */
++#define MSCAN_CANIDMR7_OFFSET 0x3D /* Identifier Mask Registers */
++ mdelay(20);
++ out_8(mscan + MSCAN_CANIDMR0_OFFSET, 0xFF);
++ out_8(mscan + MSCAN_CANIDMR1_OFFSET, 0xFF);
++ out_8(mscan + MSCAN_CANIDMR2_OFFSET, 0xFF);
++ out_8(mscan + MSCAN_CANIDMR3_OFFSET, 0xFF);
++ out_8(mscan + MSCAN_CANIDMR4_OFFSET, 0xFF);
++ out_8(mscan + MSCAN_CANIDMR5_OFFSET, 0xFF);
++ out_8(mscan + MSCAN_CANIDMR6_OFFSET, 0xFF);
++ out_8(mscan + MSCAN_CANIDMR7_OFFSET, 0xFF);
++
++ /* Come out of Init */
++ reg = in_8(mscan);
++ reg &= ~0x1;
++ reg |= 0x4; //Set WUPE
++ out_8(mscan, reg);
++
++ mdelay(20);
++ /* Enabling the Interrupts for MSCAN 0 */
++ reg = in_8(mscan + 9);
++ reg |= 0xFF;
++ out_8(mscan + 9, reg);
++}
++#endif
++void mpc512x_pm_test_setup(void)
++{
++ struct device_node *ofn;
++ u32 reg;
++ u32 *clock = NULL;
++ const u32 *cell_index;
++
++ if (once == 0) {
++#ifndef CONFIG_MPC5125_TWR
++ /* Enable the BDLC/MSCAN Periperal Clock */
++ clock = ioremap((u32) get_immrbase() + 0xF00, 0x100);
++ reg = in_be32((u32 *) ((u32) clock + 0x08));
++ reg |= 0x02000000;
++ out_be32((u32 *) ((u32) clock + 0x08), reg);
++ iounmap(clock);
++
++ xgpio = ioremap((u32) get_immrbase() + 0x1100, 0x100);
++ xmscan = ioremap((u32) get_immrbase() + 0x1300, 0x100);
++
++ /*Setup the irq handlers with dummy event ids */
++ ofn = of_find_compatible_node(NULL, NULL, "fsl,mpc5125-gpio");
++ irq = irq_of_parse_and_map(ofn, 0);
++ of_node_put(ofn);
++ reg =
++ request_irq(irq, mpc51xx_gpio_handler, IRQF_PERCPU, //|IRQF_DISABLED|IRQF_SHARED
++ "mpx512x_test_gpio", (void *)0);
++
++ for_each_compatible_node(ofn, NULL, "fsl,mpc5121-mscan") {
++ cell_index = of_get_property(ofn, "cell-index", NULL);
++ if (cell_index && *cell_index == 0) {
++ irq = irq_of_parse_and_map(ofn, 0);
++ reg = request_irq(irq, mpc51xx_can0_handler, IRQF_PERCPU,
++ "mpx512x_test_can0", (void *)1);
++ }
++ if (cell_index && *cell_index == 1) {
++ irq = irq_of_parse_and_map(ofn, 0);
++ reg = request_irq(irq, mpc51xx_can1_handler, IRQF_PERCPU,
++ "mpx512x_test_can1", (void *)2);
++ }
++ }
++
++ // xgpio = ioremap((u32) get_immrbase() + 0x1100, 0x100);
++ // xmscan = ioremap((u32) get_immrbase() + 0x1300, 0x100);
++
++ /* Setup the CAN modules for testing wakeup */
++ mpc512x_can_setup(xmscan);
++ mpc512x_can_setup(xmscan + 0x80);
++ out_be32((u32 *) ((u32) xgpio + 0xC), 0xFFFFFFFF);
++ mpc512x_set_gpio_wakeup(28, 3);
++ mpc512x_set_gpio_wakeup(29, 3);
++ mpc512x_set_gpio_wakeup(30, 3);
++ mpc512x_set_gpio_wakeup(31, 3);
++#else
++ xgpio = ioremap((u32) get_immrbase() + 0x1100, 0x100);
++
++ /*Setup the irq handlers with dummy event ids */
++ ofn = of_find_compatible_node(NULL, NULL, "fsl,mpc5125-gpio");
++ irq = irq_of_parse_and_map(ofn, 0);
++ of_node_put(ofn);
++ reg =
++ request_irq(irq, mpc51xx_gpio_handler, IRQF_SHARED, //|IRQF_DISABLED|IRQF_SHARED
++ "mpx512x_test_gpio", (void *)xgpio);
++ mpc512x_set_gpio_wakeup(0, 3);
++
++#endif
++ once = 1;
++ }
++}
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/mpc512x.S linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc512x.S
+--- linux-2.6.29/arch/powerpc/platforms/512x/mpc512x.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc512x.S 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,117 @@
++#include <asm/reg.h>
++#include <asm/ppc_asm.h>
++#include <asm/processor.h>
++#include <asm/page.h>
++#include <asm/cache.h>
++
++#define NUM_CACHE_LINES (128*8)
++
++ /* this variable added to reserve 0x20*4 bytes.
++ * This value has been derived by counting the
++ * number of lines of the function "code_atzero".
++ * In case if the size of this function increases
++ * the number of bytes have to increased accordi-
++ * ngly.
++ */
++ .data
++mpc5121_data_temp:
++ .space 0x20*4
++
++ .text
++ .globl mpc5121_copy_pmcclr
++mpc5121_copy_pmcclr:
++ /* Coming here with interrupts disabled */
++ /* storing the content at 0x0 location
++ * to mpc512_data_temp space */
++ lis r6, CONFIG_KERNEL_START@h
++ mr r4, r6
++ li r3, (code_atzero_end - code_atzero)/4
++ mtctr r3
++ lis r3, mpc5121_data_temp@h
++ ori r3, r3, mpc5121_data_temp@l
++ /* loops here till the counter is zero */
++loop:
++ lwz r5, 0(r4)
++ stw r5, 0(r3)
++ addi r3, r3, 4
++ addi r4, r4, 4
++ bdnz loop
++
++ /* Copy code to Location 0x0 */
++ mr r4, r6
++ li r3, (code_atzero_end - code_atzero)/4
++ mtctr r3
++ lis r3, code_atzero@h
++ ori r3, r3, code_atzero@l
++1:
++ lwz r5, 0(r3)
++ stw r5, 0(r4)
++ addi r3, r3, 4
++ addi r4, r4, 4
++ bdnz 1b
++
++ /* Copy the jump to 0x0 code at 0x500*/
++ lwz r5, 0x500(r6)
++ stw r5, 0(r6)
++ lwz r5, 8(r6)
++ stw r5, 0x500(r6)
++
++ /* Flush the cache */
++ lis r3, CONFIG_KERNEL_START@h
++ ori r3, r3, CONFIG_KERNEL_START@l
++
++ /* Let us load data starting from 0x600 loc */
++ addi r3, r3, 0x600
++ li r4, NUM_CACHE_LINES
++ mtctr r4
++1:
++ lwz r4, 0(r3)
++ addi r3, r3, L1_CACHE_BYTES /* Next line, please */
++ bdnz 1b
++ sync; isync
++ blr
++
++ .globl mpc5121_reinstall_handler
++mpc5121_reinstall_handler:
++
++ /* Rewrite original code at 0x500 */
++ lis r6, CONFIG_KERNEL_START@h
++ lwz r5, 0(r6)
++ stw r5, 0x500(r6)
++ /* restoring content at 0x0 location */
++ mr r4, r6
++ li r3, (code_atzero_end - code_atzero)/4
++ mtctr r3
++ lis r3, mpc5121_data_temp@h
++ ori r3, r3, mpc5121_data_temp@l
++ /* loops here till the counter is zero */
++loop1:
++ lwz r5, 0(r3)
++ stw r5, 0(r4)
++ addi r3, r3, 4
++ addi r4, r4, 4
++ bdnz loop1
++ blr
++
++code_atzero:
++ .long 0x0 /*Space reserved for copying first word of code from 0x500 */
++ ba 0x504
++ ba 0xc /* This code is not executed. This code is copied to 0x500 */
++ mtspr SPRN_SPRG0, r3
++ mtspr SPRN_SPRG1, r4
++ mfspr r3, 311
++ addi r3, r3, 0x1000 /* Assuming that MBAR is aligned to this size */
++ lwz r4, 0x4(r3)
++ stw r4, 0x4(r3)
++ /* clearing GPIO evnet registers */
++ mfspr r3, 311
++ /* getting offset of GPIO */
++ addi r3, r3,0x1100
++ lwz r4, 0xC(r3)
++ stw r4, 0xC(r3)
++ mfspr r3, SPRN_SPRG0
++ mfspr r4, SPRN_SPRG1
++ ba 0x0
++code_atzero_end:
++ b code_atzero_end /* Should never reach here*/
++
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/mpc512x_shared.c linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc512x_shared.c
+--- linux-2.6.29/arch/powerpc/platforms/512x/mpc512x_shared.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/mpc512x_shared.c 2010-04-13 20:23:26.000000000 +0200
+@@ -23,7 +23,7 @@
+ #include <asm/time.h>
+
+ #include "mpc512x.h"
+-
++#ifndef CONFIG_MPC5125_TWR
+ unsigned long
+ mpc512x_find_ips_freq(struct device_node *node)
+ {
+@@ -46,7 +46,7 @@
+ return p_ips_freq ? *p_ips_freq : 0;
+ }
+ EXPORT_SYMBOL(mpc512x_find_ips_freq);
+-
++#endif
+ void __init mpc512x_init_IRQ(void)
+ {
+ struct device_node *np;
+@@ -69,9 +69,16 @@
+ * Nodes to do bus probe on, soc and localbus
+ */
+ static struct of_device_id __initdata of_bus_ids[] = {
++ { .name = "soc", },
++ { .name = "localbus", },
++ { .compatible = "fsl,mpc5121-nfc", },
++ { .compatible = "fsl,mpc5121-mbx", },
++ {},
++/*
+ { .compatible = "fsl,mpc5121-immr", },
+ { .compatible = "fsl,mpc5121-localbus", },
+ {},
++*/
+ };
+
+ void __init mpc512x_declare_of_platform_devices(void)
+diff -Naur linux-2.6.29/arch/powerpc/platforms/512x/pci.c linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/pci.c
+--- linux-2.6.29/arch/powerpc/platforms/512x/pci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/platforms/512x/pci.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,83 @@
++/*
++ * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * Original copied from 83xx/pci.c:
++ *
++ * FSL SoC setup code
++ *
++ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++
++#include <asm/system.h>
++#include <asm/atomic.h>
++#include <asm/io.h>
++#include <asm/pci-bridge.h>
++#include <asm/prom.h>
++#include <sysdev/fsl_soc.h>
++
++#undef DEBUG
++
++#ifdef DEBUG
++#define DBG(x...) printk(x)
++#else
++#define DBG(x...)
++#endif
++
++int __init mpc512x_add_bridge(struct device_node *dev)
++{
++ int len;
++ struct pci_controller *hose;
++ struct resource rsrc;
++ const int *bus_range;
++ int has_address = 0;
++ phys_addr_t immr = get_immrbase();
++
++ DBG("Adding PCI host bridge %s\n", dev->full_name);
++
++ /* Fetch host bridge registers address */
++ has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
++
++ /* Get bus range if any */
++ bus_range = of_get_property(dev, "bus-range", &len);
++ if (bus_range == NULL || len < 2 * sizeof(int)) {
++ printk(KERN_WARNING "Can't get bus-range for %s, assume"
++ " bus 0\n", dev->full_name);
++ }
++
++ hose = pcibios_alloc_controller(dev);
++ if (!hose)
++ return -ENOMEM;
++
++ hose->first_busno = bus_range ? bus_range[0] : 0;
++ hose->last_busno = bus_range ? bus_range[1] : 0xff;
++
++ setup_indirect_pci(hose, immr + 0x8300, immr + 0x8304, 0);
++
++ printk(KERN_INFO "Found MPC512x PCI host bridge at 0x%016llx. "
++ "Firmware bus number: %d->%d\n",
++ (unsigned long long)rsrc.start, hose->first_busno,
++ hose->last_busno);
++
++ DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
++ hose, hose->cfg_addr, hose->cfg_data);
++
++ /* Interpret the "ranges" property */
++ /* This also maps the I/O region and sets isa_io/mem_base */
++ pci_process_bridge_OF_ranges(hose, dev, 1);
++
++ return 0;
++}
+diff -Naur linux-2.6.29/arch/powerpc/sysdev/fsl_soc.c linux-2.6.29-v2010041601/arch/powerpc/sysdev/fsl_soc.c
+--- linux-2.6.29/arch/powerpc/sysdev/fsl_soc.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/sysdev/fsl_soc.c 2010-04-13 20:23:26.000000000 +0200
+@@ -43,6 +43,12 @@
+ extern void init_fcc_ioports(struct fs_platform_info*);
+ extern void init_fec_ioports(struct fs_platform_info*);
+ extern void init_smc_ioports(struct fs_uart_platform_info*);
++
++extern int usb_platform_dr_init(struct platform_device *);
++extern void usb_platform_dr_uninit(struct fsl_usb2_platform_data *);
++extern int usb_platform_mph_init(struct platform_device *);
++extern void usb_platform_mph_uninit(struct fsl_usb2_platform_data *);
++
+ static phys_addr_t immrbase = -1;
+
+ phys_addr_t get_immrbase(void)
+@@ -55,18 +61,10 @@
+ soc = of_find_node_by_type(NULL, "soc");
+ if (soc) {
+ int size;
+- u32 naddr;
+- const u32 *prop = of_get_property(soc, "#address-cells", &size);
++ const void *prop = of_get_property(soc, "reg", &size);
+
+- if (prop && size == 4)
+- naddr = *prop;
+- else
+- naddr = 2;
+-
+- prop = of_get_property(soc, "ranges", &size);
+ if (prop)
+- immrbase = of_translate_address(soc, prop + naddr);
+-
++ immrbase = of_translate_address(soc, prop);
+ of_node_put(soc);
+ }
+
+@@ -75,34 +73,7 @@
+
+ EXPORT_SYMBOL(get_immrbase);
+
+-static u32 sysfreq = -1;
+-
+-u32 fsl_get_sys_freq(void)
+-{
+- struct device_node *soc;
+- const u32 *prop;
+- int size;
+-
+- if (sysfreq != -1)
+- return sysfreq;
+-
+- soc = of_find_node_by_type(NULL, "soc");
+- if (!soc)
+- return -1;
+-
+- prop = of_get_property(soc, "clock-frequency", &size);
+- if (!prop || size != sizeof(*prop) || *prop == 0)
+- prop = of_get_property(soc, "bus-frequency", &size);
+-
+- if (prop && size == sizeof(*prop))
+- sysfreq = *prop;
+-
+- of_node_put(soc);
+- return sysfreq;
+-}
+-EXPORT_SYMBOL(fsl_get_sys_freq);
+-
+-#if defined(CONFIG_CPM2) || defined(CONFIG_QUICC_ENGINE) || defined(CONFIG_8xx)
++#if defined(CONFIG_CPM2) || defined(CONFIG_8xx)
+
+ static u32 brgfreq = -1;
+
+@@ -127,21 +98,11 @@
+
+ /* Legacy device binding -- will go away when no users are left. */
+ node = of_find_node_by_type(NULL, "cpm");
+- if (!node)
+- node = of_find_compatible_node(NULL, NULL, "fsl,qe");
+- if (!node)
+- node = of_find_node_by_type(NULL, "qe");
+-
+ if (node) {
+ prop = of_get_property(node, "brg-frequency", &size);
+ if (prop && size == 4)
+ brgfreq = *prop;
+
+- if (brgfreq == -1 || brgfreq == 0) {
+- prop = of_get_property(node, "bus-frequency", &size);
+- if (prop && size == 4)
+- brgfreq = *prop / 2;
+- }
+ of_node_put(node);
+ }
+
+@@ -176,36 +137,329 @@
+ EXPORT_SYMBOL(get_baudrate);
+ #endif /* CONFIG_CPM2 */
+
+-#ifdef CONFIG_FIXED_PHY
+-static int __init of_add_fixed_phys(void)
++static int __init gfar_mdio_of_init(void)
+ {
++ struct device_node *np;
++ unsigned int i;
++ struct platform_device *mdio_dev;
++ struct resource res;
+ int ret;
++
++ for (np = NULL, i = 0;
++ (np = of_find_compatible_node(np, "mdio", "gianfar")) != NULL;
++ i++) {
++ int k;
++ struct device_node *child = NULL;
++ struct gianfar_mdio_data mdio_data;
++
++ memset(&res, 0, sizeof(res));
++ memset(&mdio_data, 0, sizeof(mdio_data));
++
++ ret = of_address_to_resource(np, 0, &res);
++ if (ret)
++ goto err;
++
++ mdio_dev =
++ platform_device_register_simple("fsl-gianfar_mdio",
++ res.start, &res, 1);
++ if (IS_ERR(mdio_dev)) {
++ ret = PTR_ERR(mdio_dev);
++ goto err;
++ }
++
++ for (k = 0; k < 32; k++)
++ mdio_data.irq[k] = PHY_POLL;
++
++ while ((child = of_get_next_child(np, child)) != NULL) {
++ int irq = irq_of_parse_and_map(child, 0);
++ if (irq != NO_IRQ) {
++ const u32 *id = of_get_property(child,
++ "reg", NULL);
++ mdio_data.irq[*id] = irq;
++ }
++ }
++
++ ret =
++ platform_device_add_data(mdio_dev, &mdio_data,
++ sizeof(struct gianfar_mdio_data));
++ if (ret)
++ goto unreg;
++ }
++
++ return 0;
++
++unreg:
++ platform_device_unregister(mdio_dev);
++err:
++ return ret;
++}
++
++arch_initcall(gfar_mdio_of_init);
++#if 0
++static const char *gfar_tx_intr = "tx";
++static const char *gfar_rx_intr = "rx";
++static const char *gfar_err_intr = "error";
++
++
++static int __init gfar_of_init(void)
++{
+ struct device_node *np;
+- u32 *fixed_link;
+- struct fixed_phy_status status = {};
++ unsigned int i;
++ struct platform_device *gfar_dev;
++ struct resource res;
++ int ret;
+
+- for_each_node_by_name(np, "ethernet") {
+- fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL);
+- if (!fixed_link)
+- continue;
++ for (np = NULL, i = 0;
++ (np = of_find_compatible_node(np, "network", "gianfar")) != NULL;
++ i++) {
++ struct resource r[4];
++ struct device_node *phy, *mdio;
++ struct gianfar_platform_data gfar_data;
++ const unsigned int *id;
++ const char *model;
++ const char *ctype;
++ const void *mac_addr;
++ const phandle *ph;
++ int n_res = 2;
+
+- status.link = 1;
+- status.duplex = fixed_link[1];
+- status.speed = fixed_link[2];
+- status.pause = fixed_link[3];
+- status.asym_pause = fixed_link[4];
++ memset(r, 0, sizeof(r));
++ memset(&gfar_data, 0, sizeof(gfar_data));
+
+- ret = fixed_phy_add(PHY_POLL, fixed_link[0], &status);
++ ret = of_address_to_resource(np, 0, &r[0]);
++ if (ret)
++ goto err;
++
++ of_irq_to_resource(np, 0, &r[1]);
++
++ model = of_get_property(np, "model", NULL);
++
++ /* If we aren't the FEC we have multiple interrupts */
++ if (model && strcasecmp(model, "FEC")) {
++ r[1].name = gfar_tx_intr;
++
++ r[2].name = gfar_rx_intr;
++ of_irq_to_resource(np, 1, &r[2]);
++
++ r[3].name = gfar_err_intr;
++ of_irq_to_resource(np, 2, &r[3]);
++
++ n_res += 2;
++ }
++
++ gfar_dev =
++ platform_device_register_simple("fsl-gianfar", i, &r[0],
++ n_res);
++
++ if (IS_ERR(gfar_dev)) {
++ ret = PTR_ERR(gfar_dev);
++ goto err;
++ }
++
++ mac_addr = of_get_mac_address(np);
++ if (mac_addr)
++ memcpy(gfar_data.mac_addr, mac_addr, 6);
++
++ if (model && !strcasecmp(model, "TSEC"))
++ gfar_data.device_flags =
++ FSL_GIANFAR_DEV_HAS_GIGABIT |
++ FSL_GIANFAR_DEV_HAS_COALESCE |
++ FSL_GIANFAR_DEV_HAS_RMON |
++ FSL_GIANFAR_DEV_HAS_MULTI_INTR;
++ if (model && !strcasecmp(model, "eTSEC"))
++ gfar_data.device_flags =
++ FSL_GIANFAR_DEV_HAS_GIGABIT |
++ FSL_GIANFAR_DEV_HAS_COALESCE |
++ FSL_GIANFAR_DEV_HAS_RMON |
++ FSL_GIANFAR_DEV_HAS_MULTI_INTR |
++ FSL_GIANFAR_DEV_HAS_CSUM |
++ FSL_GIANFAR_DEV_HAS_VLAN |
++ FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
++
++ ctype = of_get_property(np, "phy-connection-type", NULL);
++
++ /* We only care about rgmii-id. The rest are autodetected */
++ if (ctype && !strcmp(ctype, "rgmii-id"))
++ gfar_data.interface = PHY_INTERFACE_MODE_RGMII_ID;
++ else
++ gfar_data.interface = PHY_INTERFACE_MODE_MII;
++
++ ph = of_get_property(np, "phy-handle", NULL);
++ phy = of_find_node_by_phandle(*ph);
++
++ if (phy == NULL) {
++ ret = -ENODEV;
++ goto unreg;
++ }
++
++ mdio = of_get_parent(phy);
++
++ id = of_get_property(phy, "reg", NULL);
++ ret = of_address_to_resource(mdio, 0, &res);
+ if (ret) {
+- of_node_put(np);
+- return ret;
++ of_node_put(phy);
++ of_node_put(mdio);
++ goto unreg;
+ }
++
++ gfar_data.phy_id = *id;
++ gfar_data.bus_id = res.start;
++
++ of_node_put(phy);
++ of_node_put(mdio);
++
++ ret =
++ platform_device_add_data(gfar_dev, &gfar_data,
++ sizeof(struct
++ gianfar_platform_data));
++ if (ret)
++ goto unreg;
+ }
+
+ return 0;
++
++unreg:
++ platform_device_unregister(gfar_dev);
++err:
++ return ret;
+ }
+-arch_initcall(of_add_fixed_phys);
+-#endif /* CONFIG_FIXED_PHY */
++
++arch_initcall(gfar_of_init);
++
++#endif
++
++#ifdef CONFIG_I2C_BOARDINFO
++#include <linux/i2c.h>
++struct i2c_driver_device {
++ char *of_device;
++ char *i2c_driver;
++ char *i2c_type;
++};
++
++static struct i2c_driver_device i2c_devices[] __initdata = {
++ {"ricoh,rs5c372a", "rtc-rs5c372", "rs5c372a",},
++ {"ricoh,rs5c372b", "rtc-rs5c372", "rs5c372b",},
++ {"ricoh,rv5c386", "rtc-rs5c372", "rv5c386",},
++ {"ricoh,rv5c387a", "rtc-rs5c372", "rv5c387a",},
++ {"dallas,ds1307", "rtc-ds1307", "ds1307",},
++ {"dallas,ds1337", "rtc-ds1307", "ds1337",},
++ {"dallas,ds1338", "rtc-ds1307", "ds1338",},
++ {"dallas,ds1339", "rtc-ds1307", "ds1339",},
++ {"dallas,ds1340", "rtc-ds1307", "ds1340",},
++ {"stm,m41t00", "rtc-ds1307", "m41t00"},
++ {"dallas,ds1374", "rtc-ds1374", "rtc-ds1374",},
++ {"sd,sd2068", "rtc-sd2068", "rtc-sd2068",},
++ {"topstd,chacha_mt4", "chacha_mt4", "chacha_mt4",},
++ {"mosart,ma17p0x", "ma17p0x", "ma17p0x",},
++};
++
++static int __init of_find_i2c_driver(struct device_node *node,
++ struct i2c_board_info *info)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) {
++ if (!of_device_is_compatible(node, i2c_devices[i].of_device))
++ continue;
++
++ if (/*strlcpy(info->driver_name, i2c_devices[i].i2c_driver,
++ KOBJ_NAME_LEN) >= KOBJ_NAME_LEN ||*/
++ strlcpy(info->type, i2c_devices[i].i2c_type,
++ I2C_NAME_SIZE) >= I2C_NAME_SIZE)
++ {
++ /*printk("%s() line:%d\n",__FUNCTION__,__LINE__);*/
++ return -ENOMEM;
++ }
++ return 0;
++ }
++ return -ENODEV;
++}
++
++static void __init of_register_i2c_devices(struct device_node *adap_node,
++ int bus_num)
++{
++ struct device_node *node = NULL;
++
++ while ((node = of_get_next_child(adap_node, node))) {
++ struct i2c_board_info info = {};
++ const u32 *addr;
++ int len;
++
++ addr = of_get_property(node, "reg", &len);
++ if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) {
++ printk(KERN_WARNING "fsl_soc.c: invalid i2c device entry\n");
++ continue;
++ }
++
++ info.irq = irq_of_parse_and_map(node, 0);
++ if (info.irq == NO_IRQ)
++ info.irq = -1;
++
++ if (of_find_i2c_driver(node, &info) < 0)
++ continue;
++
++ info.addr = *addr;
++
++ i2c_register_board_info(bus_num, &info, 1);
++ }
++}
++
++static int __init fsl_i2c_of_init(void)
++{
++ struct device_node *np;
++ unsigned int i = 0;
++ struct platform_device *i2c_dev;
++ int ret;
++
++ for_each_compatible_node(np, NULL, "fsl-i2c") {
++ struct resource r[2];
++ struct fsl_i2c_platform_data i2c_data;
++ const unsigned char *flags = NULL;
++
++ memset(&r, 0, sizeof(r));
++ memset(&i2c_data, 0, sizeof(i2c_data));
++
++ ret = of_address_to_resource(np, 0, &r[0]);
++ if (ret)
++ goto err;
++
++ of_irq_to_resource(np, 0, &r[1]);
++
++ i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2);
++ if (IS_ERR(i2c_dev)) {
++ ret = PTR_ERR(i2c_dev);
++ goto err;
++ }
++
++ i2c_data.device_flags = 0;
++ flags = of_get_property(np, "dfsrr", NULL);
++ if (flags)
++ i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
++
++ flags = of_get_property(np, "fsl5200-clocking", NULL);
++ if (flags)
++ i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
++
++ ret =
++ platform_device_add_data(i2c_dev, &i2c_data,
++ sizeof(struct
++ fsl_i2c_platform_data));
++ if (ret)
++ goto unreg;
++
++ of_register_i2c_devices(np, i++);
++ }
++
++ return 0;
++
++unreg:
++ platform_device_unregister(i2c_dev);
++err:
++ return ret;
++}
++
++arch_initcall(fsl_i2c_of_init);
++#endif
++
+
+ #ifdef CONFIG_PPC_83xx
+ static int __init mpc83xx_wdt_init(void)
+@@ -272,12 +526,14 @@
+ static int __init fsl_usb_of_init(void)
+ {
+ struct device_node *np;
+- unsigned int i = 0;
+- struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_host = NULL,
+- *usb_dev_dr_client = NULL;
++ unsigned int i;
++ struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_otg = NULL,
++ *usb_dev_dr_host = NULL, *usb_dev_dr_client = NULL;
+ int ret;
+
+- for_each_compatible_node(np, NULL, "fsl-usb2-mph") {
++ for (np = NULL, i = 0;
++ (np = of_find_compatible_node(np, "usb", "fsl-usb2-mph")) != NULL;
++ i++) {
+ struct resource r[2];
+ struct fsl_usb2_platform_data usb_data;
+ const unsigned char *prop = NULL;
+@@ -311,19 +567,25 @@
+ if (prop)
+ usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
+
++ if (of_get_property(np, "big-endian-regs", NULL))
++ usb_data.big_endian_mmio = 1;
+ prop = of_get_property(np, "phy_type", NULL);
+ usb_data.phy_mode = determine_usb_phy(prop);
+
++ usb_data.platform_init = usb_platform_mph_init;
++ usb_data.platform_uninit = usb_platform_mph_uninit;
++
+ ret =
+ platform_device_add_data(usb_dev_mph, &usb_data,
+ sizeof(struct
+ fsl_usb2_platform_data));
+ if (ret)
+ goto unreg_mph;
+- i++;
+ }
+
+- for_each_compatible_node(np, NULL, "fsl-usb2-dr") {
++ for (np = NULL;
++ (np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL;
++ i++) {
+ struct resource r[2];
+ struct fsl_usb2_platform_data usb_data;
+ const unsigned char *prop = NULL;
+@@ -357,26 +619,47 @@
+ }
+ } else if (prop && !strcmp(prop, "otg")) {
+ usb_data.operating_mode = FSL_USB2_DR_OTG;
++ usb_dev_dr_otg = platform_device_register_simple(
++ "fsl-usb2-otg", i, r, 2);
++ if (IS_ERR(usb_dev_dr_otg)) {
++ ret = PTR_ERR(usb_dev_dr_otg);
++ goto unreg_dr;
++ }
+ usb_dev_dr_host = platform_device_register_simple(
+ "fsl-ehci", i, r, 2);
+ if (IS_ERR(usb_dev_dr_host)) {
+ ret = PTR_ERR(usb_dev_dr_host);
+- goto err;
++ goto unreg_dr;
+ }
+ usb_dev_dr_client = platform_device_register_simple(
+ "fsl-usb2-udc", i, r, 2);
+ if (IS_ERR(usb_dev_dr_client)) {
+ ret = PTR_ERR(usb_dev_dr_client);
+- goto err;
++ goto unreg_dr;
+ }
+ } else {
+ ret = -EINVAL;
+ goto err;
+ }
++ if (of_get_property(np, "big-endian-regs", NULL))
++ usb_data.big_endian_mmio = 1;
+
+ prop = of_get_property(np, "phy_type", NULL);
+ usb_data.phy_mode = determine_usb_phy(prop);
+-
++
++ usb_data.platform_init = usb_platform_dr_init;
++ usb_data.platform_uninit = usb_platform_dr_uninit;
++
++
++ if (usb_dev_dr_otg) {
++ usb_dev_dr_otg->dev.coherent_dma_mask = 0xffffffffUL;
++ usb_dev_dr_otg->dev.dma_mask = &usb_dev_dr_otg->
++ dev.coherent_dma_mask;
++ if ((ret = platform_device_add_data(usb_dev_dr_otg,
++ &usb_data, sizeof(struct
++ fsl_usb2_platform_data))))
++ goto unreg_dr;
++ }
+ if (usb_dev_dr_host) {
+ usb_dev_dr_host->dev.coherent_dma_mask = 0xffffffffUL;
+ usb_dev_dr_host->dev.dma_mask = &usb_dev_dr_host->
+@@ -395,7 +678,6 @@
+ fsl_usb2_platform_data))))
+ goto unreg_dr;
+ }
+- i++;
+ }
+ return 0;
+
+@@ -404,6 +686,8 @@
+ platform_device_unregister(usb_dev_dr_host);
+ if (usb_dev_dr_client)
+ platform_device_unregister(usb_dev_dr_client);
++ if (usb_dev_dr_otg)
++ platform_device_unregister(usb_dev_dr_otg);
+ unreg_mph:
+ if (usb_dev_mph)
+ platform_device_unregister(usb_dev_mph);
+@@ -413,17 +697,572 @@
+
+ arch_initcall(fsl_usb_of_init);
+
+-static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
+- struct spi_board_info *board_infos,
+- unsigned int num_board_infos,
+- void (*activate_cs)(u8 cs, u8 polarity),
+- void (*deactivate_cs)(u8 cs, u8 polarity))
++#ifndef CONFIG_PPC_CPM_NEW_BINDING
++#ifdef CONFIG_CPM2
++
++extern void init_scc_ioports(struct fs_uart_platform_info*);
++
++static const char fcc_regs[] = "fcc_regs";
++static const char fcc_regs_c[] = "fcc_regs_c";
++static const char fcc_pram[] = "fcc_pram";
++static char bus_id[9][BUS_ID_SIZE];
++
++static int __init fs_enet_of_init(void)
+ {
+ struct device_node *np;
+- unsigned int i = 0;
++ unsigned int i;
++ struct platform_device *fs_enet_dev;
++ struct resource res;
++ int ret;
++
++ for (np = NULL, i = 0;
++ (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL;
++ i++) {
++ struct resource r[4];
++ struct device_node *phy, *mdio;
++ struct fs_platform_info fs_enet_data;
++ const unsigned int *id, *phy_addr, *phy_irq;
++ const void *mac_addr;
++ const phandle *ph;
++ const char *model;
++
++ memset(r, 0, sizeof(r));
++ memset(&fs_enet_data, 0, sizeof(fs_enet_data));
++
++ ret = of_address_to_resource(np, 0, &r[0]);
++ if (ret)
++ goto err;
++ r[0].name = fcc_regs;
++
++ ret = of_address_to_resource(np, 1, &r[1]);
++ if (ret)
++ goto err;
++ r[1].name = fcc_pram;
++
++ ret = of_address_to_resource(np, 2, &r[2]);
++ if (ret)
++ goto err;
++ r[2].name = fcc_regs_c;
++ fs_enet_data.fcc_regs_c = r[2].start;
++
++ of_irq_to_resource(np, 0, &r[3]);
++
++ fs_enet_dev =
++ platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4);
++
++ if (IS_ERR(fs_enet_dev)) {
++ ret = PTR_ERR(fs_enet_dev);
++ goto err;
++ }
++
++ model = of_get_property(np, "model", NULL);
++ if (model == NULL) {
++ ret = -ENODEV;
++ goto unreg;
++ }
++
++ mac_addr = of_get_mac_address(np);
++ if (mac_addr)
++ memcpy(fs_enet_data.macaddr, mac_addr, 6);
++
++ ph = of_get_property(np, "phy-handle", NULL);
++ phy = of_find_node_by_phandle(*ph);
++
++ if (phy == NULL) {
++ ret = -ENODEV;
++ goto unreg;
++ }
++
++ phy_addr = of_get_property(phy, "reg", NULL);
++ fs_enet_data.phy_addr = *phy_addr;
++
++ phy_irq = of_get_property(phy, "interrupts", NULL);
++
++ id = of_get_property(np, "device-id", NULL);
++ fs_enet_data.fs_no = *id;
++ strcpy(fs_enet_data.fs_type, model);
++
++ mdio = of_get_parent(phy);
++ ret = of_address_to_resource(mdio, 0, &res);
++ if (ret) {
++ of_node_put(phy);
++ of_node_put(mdio);
++ goto unreg;
++ }
++
++ fs_enet_data.clk_rx = *((u32 *)of_get_property(np,
++ "rx-clock", NULL));
++ fs_enet_data.clk_tx = *((u32 *)of_get_property(np,
++ "tx-clock", NULL));
++
++ if (strstr(model, "FCC")) {
++ int fcc_index = *id - 1;
++ const unsigned char *mdio_bb_prop;
++
++ fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0);
++ fs_enet_data.rx_ring = 32;
++ fs_enet_data.tx_ring = 32;
++ fs_enet_data.rx_copybreak = 240;
++ fs_enet_data.use_napi = 0;
++ fs_enet_data.napi_weight = 17;
++ fs_enet_data.mem_offset = FCC_MEM_OFFSET(fcc_index);
++ fs_enet_data.cp_page = CPM_CR_FCC_PAGE(fcc_index);
++ fs_enet_data.cp_block = CPM_CR_FCC_SBLOCK(fcc_index);
++
++ snprintf((char*)&bus_id[(*id)], BUS_ID_SIZE, "%x:%02x",
++ (u32)res.start, fs_enet_data.phy_addr);
++ fs_enet_data.bus_id = (char*)&bus_id[(*id)];
++ fs_enet_data.init_ioports = init_fcc_ioports;
++
++ mdio_bb_prop = of_get_property(phy, "bitbang", NULL);
++ if (mdio_bb_prop) {
++ struct platform_device *fs_enet_mdio_bb_dev;
++ struct fs_mii_bb_platform_info fs_enet_mdio_bb_data;
++
++ fs_enet_mdio_bb_dev =
++ platform_device_register_simple("fsl-bb-mdio",
++ i, NULL, 0);
++ memset(&fs_enet_mdio_bb_data, 0,
++ sizeof(struct fs_mii_bb_platform_info));
++ fs_enet_mdio_bb_data.mdio_dat.bit =
++ mdio_bb_prop[0];
++ fs_enet_mdio_bb_data.mdio_dir.bit =
++ mdio_bb_prop[1];
++ fs_enet_mdio_bb_data.mdc_dat.bit =
++ mdio_bb_prop[2];
++ fs_enet_mdio_bb_data.mdio_port =
++ mdio_bb_prop[3];
++ fs_enet_mdio_bb_data.mdc_port =
++ mdio_bb_prop[4];
++ fs_enet_mdio_bb_data.delay =
++ mdio_bb_prop[5];
++
++ fs_enet_mdio_bb_data.irq[0] = phy_irq[0];
++ fs_enet_mdio_bb_data.irq[1] = -1;
++ fs_enet_mdio_bb_data.irq[2] = -1;
++ fs_enet_mdio_bb_data.irq[3] = phy_irq[0];
++ fs_enet_mdio_bb_data.irq[31] = -1;
++
++ fs_enet_mdio_bb_data.mdio_dat.offset =
++ (u32)&cpm2_immr->im_ioport.iop_pdatc;
++ fs_enet_mdio_bb_data.mdio_dir.offset =
++ (u32)&cpm2_immr->im_ioport.iop_pdirc;
++ fs_enet_mdio_bb_data.mdc_dat.offset =
++ (u32)&cpm2_immr->im_ioport.iop_pdatc;
++
++ ret = platform_device_add_data(
++ fs_enet_mdio_bb_dev,
++ &fs_enet_mdio_bb_data,
++ sizeof(struct fs_mii_bb_platform_info));
++ if (ret)
++ goto unreg;
++ }
++
++ of_node_put(phy);
++ of_node_put(mdio);
++
++ ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
++ sizeof(struct
++ fs_platform_info));
++ if (ret)
++ goto unreg;
++ }
++ }
++ return 0;
++
++unreg:
++ platform_device_unregister(fs_enet_dev);
++err:
++ return ret;
++}
++
++arch_initcall(fs_enet_of_init);
++
++static const char scc_regs[] = "regs";
++static const char scc_pram[] = "pram";
+
+- for_each_compatible_node(np, type, compatible) {
+- int ret;
++static int __init cpm_uart_of_init(void)
++{
++ struct device_node *np;
++ unsigned int i;
++ struct platform_device *cpm_uart_dev;
++ int ret;
++
++ for (np = NULL, i = 0;
++ (np = of_find_compatible_node(np, "serial", "cpm_uart")) != NULL;
++ i++) {
++ struct resource r[3];
++ struct fs_uart_platform_info cpm_uart_data;
++ const int *id;
++ const char *model;
++
++ memset(r, 0, sizeof(r));
++ memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
++
++ ret = of_address_to_resource(np, 0, &r[0]);
++ if (ret)
++ goto err;
++
++ r[0].name = scc_regs;
++
++ ret = of_address_to_resource(np, 1, &r[1]);
++ if (ret)
++ goto err;
++ r[1].name = scc_pram;
++
++ of_irq_to_resource(np, 0, &r[2]);
++
++ cpm_uart_dev =
++ platform_device_register_simple("fsl-cpm-scc:uart", i, &r[0], 3);
++
++ if (IS_ERR(cpm_uart_dev)) {
++ ret = PTR_ERR(cpm_uart_dev);
++ goto err;
++ }
++
++ id = of_get_property(np, "device-id", NULL);
++ cpm_uart_data.fs_no = *id;
++
++ model = of_get_property(np, "model", NULL);
++ strcpy(cpm_uart_data.fs_type, model);
++
++ cpm_uart_data.uart_clk = ppc_proc_freq;
++
++ cpm_uart_data.tx_num_fifo = 4;
++ cpm_uart_data.tx_buf_size = 32;
++ cpm_uart_data.rx_num_fifo = 4;
++ cpm_uart_data.rx_buf_size = 32;
++ cpm_uart_data.clk_rx = *((u32 *)of_get_property(np,
++ "rx-clock", NULL));
++ cpm_uart_data.clk_tx = *((u32 *)of_get_property(np,
++ "tx-clock", NULL));
++
++ ret =
++ platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
++ sizeof(struct
++ fs_uart_platform_info));
++ if (ret)
++ goto unreg;
++ }
++
++ return 0;
++
++unreg:
++ platform_device_unregister(cpm_uart_dev);
++err:
++ return ret;
++}
++
++arch_initcall(cpm_uart_of_init);
++#endif /* CONFIG_CPM2 */
++
++#ifdef CONFIG_8xx
++
++extern void init_scc_ioports(struct fs_platform_info*);
++extern int platform_device_skip(const char *model, int id);
++
++static int __init fs_enet_mdio_of_init(void)
++{
++ struct device_node *np;
++ unsigned int i;
++ struct platform_device *mdio_dev;
++ struct resource res;
++ int ret;
++
++ for (np = NULL, i = 0;
++ (np = of_find_compatible_node(np, "mdio", "fs_enet")) != NULL;
++ i++) {
++ struct fs_mii_fec_platform_info mdio_data;
++
++ memset(&res, 0, sizeof(res));
++ memset(&mdio_data, 0, sizeof(mdio_data));
++
++ ret = of_address_to_resource(np, 0, &res);
++ if (ret)
++ goto err;
++
++ mdio_dev =
++ platform_device_register_simple("fsl-cpm-fec-mdio",
++ res.start, &res, 1);
++ if (IS_ERR(mdio_dev)) {
++ ret = PTR_ERR(mdio_dev);
++ goto err;
++ }
++
++ mdio_data.mii_speed = ((((ppc_proc_freq + 4999999) / 2500000) / 2) & 0x3F) << 1;
++
++ ret =
++ platform_device_add_data(mdio_dev, &mdio_data,
++ sizeof(struct fs_mii_fec_platform_info));
++ if (ret)
++ goto unreg;
++ }
++ return 0;
++
++unreg:
++ platform_device_unregister(mdio_dev);
++err:
++ return ret;
++}
++
++arch_initcall(fs_enet_mdio_of_init);
++
++static const char *enet_regs = "regs";
++static const char *enet_pram = "pram";
++static const char *enet_irq = "interrupt";
++static char bus_id[9][BUS_ID_SIZE];
++
++static int __init fs_enet_of_init(void)
++{
++ struct device_node *np;
++ unsigned int i;
++ struct platform_device *fs_enet_dev = NULL;
++ struct resource res;
++ int ret;
++
++ for (np = NULL, i = 0;
++ (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL;
++ i++) {
++ struct resource r[4];
++ struct device_node *phy = NULL, *mdio = NULL;
++ struct fs_platform_info fs_enet_data;
++ const unsigned int *id;
++ const unsigned int *phy_addr;
++ const void *mac_addr;
++ const phandle *ph;
++ const char *model;
++
++ memset(r, 0, sizeof(r));
++ memset(&fs_enet_data, 0, sizeof(fs_enet_data));
++
++ model = of_get_property(np, "model", NULL);
++ if (model == NULL) {
++ ret = -ENODEV;
++ goto unreg;
++ }
++
++ id = of_get_property(np, "device-id", NULL);
++ fs_enet_data.fs_no = *id;
++
++ if (platform_device_skip(model, *id))
++ continue;
++
++ ret = of_address_to_resource(np, 0, &r[0]);
++ if (ret)
++ goto err;
++ r[0].name = enet_regs;
++
++ mac_addr = of_get_mac_address(np);
++ if (mac_addr)
++ memcpy(fs_enet_data.macaddr, mac_addr, 6);
++
++ ph = of_get_property(np, "phy-handle", NULL);
++ if (ph != NULL)
++ phy = of_find_node_by_phandle(*ph);
++
++ if (phy != NULL) {
++ phy_addr = of_get_property(phy, "reg", NULL);
++ fs_enet_data.phy_addr = *phy_addr;
++ fs_enet_data.has_phy = 1;
++
++ mdio = of_get_parent(phy);
++ ret = of_address_to_resource(mdio, 0, &res);
++ if (ret) {
++ of_node_put(phy);
++ of_node_put(mdio);
++ goto unreg;
++ }
++ }
++
++ model = of_get_property(np, "model", NULL);
++ strcpy(fs_enet_data.fs_type, model);
++
++ if (strstr(model, "FEC")) {
++ r[1].start = r[1].end = irq_of_parse_and_map(np, 0);
++ r[1].flags = IORESOURCE_IRQ;
++ r[1].name = enet_irq;
++
++ fs_enet_dev =
++ platform_device_register_simple("fsl-cpm-fec", i, &r[0], 2);
++
++ if (IS_ERR(fs_enet_dev)) {
++ ret = PTR_ERR(fs_enet_dev);
++ goto err;
++ }
++
++ fs_enet_data.rx_ring = 128;
++ fs_enet_data.tx_ring = 16;
++ fs_enet_data.rx_copybreak = 240;
++ fs_enet_data.use_napi = 1;
++ fs_enet_data.napi_weight = 17;
++
++ snprintf((char*)&bus_id[i], BUS_ID_SIZE, "%x:%02x",
++ (u32)res.start, fs_enet_data.phy_addr);
++ fs_enet_data.bus_id = (char*)&bus_id[i];
++ fs_enet_data.init_ioports = init_fec_ioports;
++ }
++ if (strstr(model, "SCC")) {
++ ret = of_address_to_resource(np, 1, &r[1]);
++ if (ret)
++ goto err;
++ r[1].name = enet_pram;
++
++ r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
++ r[2].flags = IORESOURCE_IRQ;
++ r[2].name = enet_irq;
++
++ fs_enet_dev =
++ platform_device_register_simple("fsl-cpm-scc", i, &r[0], 3);
++
++ if (IS_ERR(fs_enet_dev)) {
++ ret = PTR_ERR(fs_enet_dev);
++ goto err;
++ }
++
++ fs_enet_data.rx_ring = 64;
++ fs_enet_data.tx_ring = 8;
++ fs_enet_data.rx_copybreak = 240;
++ fs_enet_data.use_napi = 1;
++ fs_enet_data.napi_weight = 17;
++
++ snprintf((char*)&bus_id[i], BUS_ID_SIZE, "%s", "fixed@10:1");
++ fs_enet_data.bus_id = (char*)&bus_id[i];
++ fs_enet_data.init_ioports = init_scc_ioports;
++ }
++
++ of_node_put(phy);
++ of_node_put(mdio);
++
++ ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
++ sizeof(struct
++ fs_platform_info));
++ if (ret)
++ goto unreg;
++ }
++ return 0;
++
++unreg:
++ platform_device_unregister(fs_enet_dev);
++err:
++ return ret;
++}
++
++arch_initcall(fs_enet_of_init);
++
++static int __init fsl_pcmcia_of_init(void)
++{
++ struct device_node *np = NULL;
++ /*
++ * Register all the devices which type is "pcmcia"
++ */
++ while ((np = of_find_compatible_node(np,
++ "pcmcia", "fsl,pq-pcmcia")) != NULL)
++ of_platform_device_create(np, "m8xx-pcmcia", NULL);
++ return 0;
++}
++
++arch_initcall(fsl_pcmcia_of_init);
++
++static const char *smc_regs = "regs";
++static const char *smc_pram = "pram";
++
++static int __init cpm_smc_uart_of_init(void)
++{
++ struct device_node *np;
++ unsigned int i;
++ struct platform_device *cpm_uart_dev;
++ int ret;
++
++ for (np = NULL, i = 0;
++ (np = of_find_compatible_node(np, "serial", "cpm_uart")) != NULL;
++ i++) {
++ struct resource r[3];
++ struct fs_uart_platform_info cpm_uart_data;
++ const int *id;
++ const char *model;
++
++ memset(r, 0, sizeof(r));
++ memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
++
++ ret = of_address_to_resource(np, 0, &r[0]);
++ if (ret)
++ goto err;
++
++ r[0].name = smc_regs;
++
++ ret = of_address_to_resource(np, 1, &r[1]);
++ if (ret)
++ goto err;
++ r[1].name = smc_pram;
++
++ r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
++ r[2].flags = IORESOURCE_IRQ;
++
++ cpm_uart_dev =
++ platform_device_register_simple("fsl-cpm-smc:uart", i, &r[0], 3);
++
++ if (IS_ERR(cpm_uart_dev)) {
++ ret = PTR_ERR(cpm_uart_dev);
++ goto err;
++ }
++
++ model = of_get_property(np, "model", NULL);
++ strcpy(cpm_uart_data.fs_type, model);
++
++ id = of_get_property(np, "device-id", NULL);
++ cpm_uart_data.fs_no = *id;
++ cpm_uart_data.uart_clk = ppc_proc_freq;
++
++ cpm_uart_data.tx_num_fifo = 4;
++ cpm_uart_data.tx_buf_size = 32;
++ cpm_uart_data.rx_num_fifo = 4;
++ cpm_uart_data.rx_buf_size = 32;
++
++ ret =
++ platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
++ sizeof(struct
++ fs_uart_platform_info));
++ if (ret)
++ goto unreg;
++ }
++
++ return 0;
++
++unreg:
++ platform_device_unregister(cpm_uart_dev);
++err:
++ return ret;
++}
++
++arch_initcall(cpm_smc_uart_of_init);
++
++#endif /* CONFIG_8xx */
++#endif /* CONFIG_PPC_CPM_NEW_BINDING */
++int __init fsl_spi_init(struct spi_board_info *board_infos,
++ unsigned int num_board_infos,
++ void (*activate_cs)(u8 cs, u8 polarity),
++ void (*deactivate_cs)(u8 cs, u8 polarity))
++{
++ struct device_node *np;
++ unsigned int i;
++ const u32 *sysclk;
++
++ /* SPI controller is either clocked from QE or SoC clock */
++ np = of_find_node_by_type(NULL, "qe");
++ if (!np)
++ np = of_find_node_by_type(NULL, "soc");
++
++ if (!np)
++ return -ENODEV;
++
++ sysclk = of_get_property(np, "bus-frequency", NULL);
++ if (!sysclk)
++ return -ENODEV;
++
++ for (np = NULL, i = 1;
++ (np = of_find_compatible_node(np, "spi", "fsl_spi")) != NULL;
++ i++) {
++ int ret = 0;
+ unsigned int j;
+ const void *prop;
+ struct resource res[2];
+@@ -435,17 +1274,13 @@
+
+ memset(res, 0, sizeof(res));
+
+- pdata.sysclk = sysclk;
++ pdata.sysclk = *sysclk;
+
+ prop = of_get_property(np, "reg", NULL);
+ if (!prop)
+ goto err;
+ pdata.bus_num = *(u32 *)prop;
+
+- prop = of_get_property(np, "cell-index", NULL);
+- if (prop)
+- i = *(u32 *)prop;
+-
+ prop = of_get_property(np, "mode", NULL);
+ if (prop && !strcmp(prop, "cpu-qe"))
+ pdata.qe_mode = 1;
+@@ -456,7 +1291,7 @@
+ }
+
+ if (!pdata.max_chipselect)
+- continue;
++ goto err;
+
+ ret = of_address_to_resource(np, 0, &res[0]);
+ if (ret)
+@@ -479,46 +1314,17 @@
+ if (ret)
+ goto unreg;
+
+- ret = platform_device_add(pdev);
++ ret = platform_device_register(pdev);
+ if (ret)
+ goto unreg;
+
+- goto next;
++ continue;
+ unreg:
+ platform_device_del(pdev);
+ err:
+- pr_err("%s: registration failed\n", np->full_name);
+-next:
+- i++;
+- }
+-
+- return i;
+-}
+-
+-int __init fsl_spi_init(struct spi_board_info *board_infos,
+- unsigned int num_board_infos,
+- void (*activate_cs)(u8 cs, u8 polarity),
+- void (*deactivate_cs)(u8 cs, u8 polarity))
+-{
+- u32 sysclk = -1;
+- int ret;
+-
+-#ifdef CONFIG_QUICC_ENGINE
+- /* SPI controller is either clocked from QE or SoC clock */
+- sysclk = get_brgfreq();
+-#endif
+- if (sysclk == -1) {
+- sysclk = fsl_get_sys_freq();
+- if (sysclk == -1)
+- return -ENODEV;
++ continue;
+ }
+
+- ret = of_fsl_spi_probe(NULL, "fsl,spi", sysclk, board_infos,
+- num_board_infos, activate_cs, deactivate_cs);
+- if (!ret)
+- of_fsl_spi_probe("spi", "fsl_spi", sysclk, board_infos,
+- num_board_infos, activate_cs, deactivate_cs);
+-
+ return spi_register_board_info(board_infos, num_board_infos);
+ }
+
+@@ -560,7 +1366,41 @@
+ }
+ #endif
+
+-#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+-struct platform_diu_data_ops diu_ops;
+-EXPORT_SYMBOL(diu_ops);
+-#endif
++#ifdef CONFIG_PPC_MPC5121
++static int __init mpc512x_mbx_of_init(void)
++{
++ struct device_node *np;
++ struct platform_device *mbx_dev;
++ int ret;
++
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-mbx");
++ if (np) {
++ struct resource r[2];
++ int irq;
++
++ memset(&r, 0, sizeof(r));
++
++ ret = of_address_to_resource(np, 0, &r[0]);
++ if (ret)
++ goto err;
++
++ irq = of_irq_to_resource(np, 0, &r[1]);
++ if (irq == NO_IRQ)
++ goto err;
++
++ printk(KERN_INFO "Reserved irq %d(0x%x) for MBX\n", irq, irq);
++
++ mbx_dev = platform_device_register_simple("mpc5121-mbx",
++ 0, r, 2);
++ if (IS_ERR(mbx_dev)) {
++ ret = PTR_ERR(mbx_dev);
++ goto err;
++ }
++ }
++ return 0;
++err:
++ return ret;
++}
++
++arch_initcall(mpc512x_mbx_of_init);
++#endif /* CONFIG_PPC_512x */
+diff -Naur linux-2.6.29/arch/powerpc/sysdev/ipic.c linux-2.6.29-v2010041601/arch/powerpc/sysdev/ipic.c
+--- linux-2.6.29/arch/powerpc/sysdev/ipic.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/arch/powerpc/sysdev/ipic.c 2010-04-13 20:23:26.000000000 +0200
+@@ -902,7 +902,7 @@
+ u32 sermr;
+ u32 sercr;
+ } ipic_saved_state;
+-
++extern int fsl_deep_sleep(void);
+ static int ipic_suspend(struct sys_device *sdev, pm_message_t state)
+ {
+ struct ipic *ipic = primary_ipic;
+diff -Naur linux-2.6.29/drivers/dma/fsldma.c linux-2.6.29-v2010041601/drivers/dma/fsldma.c
+--- linux-2.6.29/drivers/dma/fsldma.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/dma/fsldma.c 2010-04-13 20:23:26.000000000 +0200
+@@ -1,22 +1,29 @@
+ /*
+- * Freescale MPC85xx, MPC83xx DMA Engine support
+- *
+- * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+- *
+- * Author:
+- * Zhang Wei <wei.zhang@freescale.com>, Jul 2007
+- * Ebony Zhu <ebony.zhu@freescale.com>, May 2007
+- *
+- * Description:
+- * DMA engine driver for Freescale MPC8540 DMA controller, which is
+- * also fit for MPC8560, MPC8555, MPC8548, MPC8641, and etc.
+- * The support for MPC8349 DMA contorller is also added.
+- *
+- * This 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.
++ * Hongjun Chen <hong-jun.chen@freescale.com>
++ *chen_yunsong <chen_yunsong@mtcera.com>
++ * Copyright (C) Freescale Semicondutor, Inc. 2007, 2008. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the Free
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
++ * The full GNU General Public License is included in this distribution in the
++ * file called COPYING.
++ */
++
++/*
++ * This driver supports an MPC5121 DMA engine, which does asynchronous
++ * copy operations.
+ */
+
+ #include <linux/init.h>
+@@ -26,996 +33,754 @@
+ #include <linux/dmaengine.h>
+ #include <linux/delay.h>
+ #include <linux/dma-mapping.h>
+-#include <linux/dmapool.h>
++#include <linux/io.h>
++#include <linux/of.h>
+ #include <linux/of_platform.h>
+
+-#include "fsldma.h"
+
+-static void dma_init(struct fsl_dma_chan *fsl_chan)
+-{
+- /* Reset the channel */
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, 0, 32);
+
+- switch (fsl_chan->feature & FSL_DMA_IP_MASK) {
+- case FSL_DMA_IP_85XX:
+- /* Set the channel to below modes:
+- * EIE - Error interrupt enable
+- * EOSIE - End of segments interrupt enable (basic mode)
+- * EOLNIE - End of links interrupt enable
+- */
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EIE
+- | FSL_DMA_MR_EOLNIE | FSL_DMA_MR_EOSIE, 32);
+- break;
+- case FSL_DMA_IP_83XX:
+- /* Set the channel to below modes:
+- * EOTIE - End-of-transfer interrupt enable
+- */
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EOTIE,
+- 32);
+- break;
+- }
++#include <asm/fsldma.h>
++#include <asm/fsldma_reg.h>
+
+-}
+
+-static void set_sr(struct fsl_dma_chan *fsl_chan, u32 val)
+-{
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->sr, val, 32);
+-}
+
+-static u32 get_sr(struct fsl_dma_chan *fsl_chan)
+-{
+- return DMA_IN(fsl_chan, &fsl_chan->reg_base->sr, 32);
+-}
++#undef DEBUG
+
+-static void set_desc_cnt(struct fsl_dma_chan *fsl_chan,
+- struct fsl_dma_ld_hw *hw, u32 count)
+-{
+- hw->count = CPU_TO_DMA(fsl_chan, count, 32);
+-}
+-
+-static void set_desc_src(struct fsl_dma_chan *fsl_chan,
+- struct fsl_dma_ld_hw *hw, dma_addr_t src)
+-{
+- u64 snoop_bits;
+-
+- snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
+- ? ((u64)FSL_DMA_SATR_SREADTYPE_SNOOP_READ << 32) : 0;
+- hw->src_addr = CPU_TO_DMA(fsl_chan, snoop_bits | src, 64);
+-}
++#ifdef DEBUG
++#define DPRINTK(fmt, args...) \
++ printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
++#else
++#define DPRINTK(fmt, args...)
++#endif
+
+-static void set_desc_dest(struct fsl_dma_chan *fsl_chan,
+- struct fsl_dma_ld_hw *hw, dma_addr_t dest)
+-{
+- u64 snoop_bits;
++static struct fsl_device *g_device;
++static struct fsl_dma_chan *g_fchan;
+
+- snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
+- ? ((u64)FSL_DMA_DATR_DWRITETYPE_SNOOP_WRITE << 32) : 0;
+- hw->dst_addr = CPU_TO_DMA(fsl_chan, snoop_bits | dest, 64);
+-}
++/* internal functions */
++static int __devinit fsl_init(void);
++static void __devexit fsl_remove(void);
++static void fsl_dma_memcpy_cleanup(struct fsl_dma_chan *fsl_chan);
+
+-static void set_desc_next(struct fsl_dma_chan *fsl_chan,
+- struct fsl_dma_ld_hw *hw, dma_addr_t next)
++static int alloc_dma_channels(struct fsl_device *device)
+ {
+- u64 snoop_bits;
++ struct fsl_dma_chan *fsl_chan;
+
+- snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
+- ? FSL_DMA_SNEN : 0;
+- hw->next_ln_addr = CPU_TO_DMA(fsl_chan, snoop_bits | next, 64);
+-}
++ device->common.chancnt = FSL_DMA_CH_NUM;
++ fsl_chan = kzalloc(sizeof(*fsl_chan) * device->common.chancnt,
++ GFP_KERNEL);
++ if (!fsl_chan) {
++ printk("Err: there is not enough memory"
++ " for channel structures!");
++ return -ENOMEM;
++ }
++ g_fchan = fsl_chan;
+
+-static void set_cdar(struct fsl_dma_chan *fsl_chan, dma_addr_t addr)
+-{
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->cdar, addr | FSL_DMA_SNEN, 64);
++ return device->common.chancnt;
+ }
+
+-static dma_addr_t get_cdar(struct fsl_dma_chan *fsl_chan)
++/* Called for DMA engine initialization */
++int fsl_dma_cfg_arbit_mode(int mode)
+ {
+- return DMA_IN(fsl_chan, &fsl_chan->reg_base->cdar, 64) & ~FSL_DMA_SNEN;
+-}
++ fsl_dma_reg *reg;
++ int i;
++ u32 temp;
+
+-static void set_ndar(struct fsl_dma_chan *fsl_chan, dma_addr_t addr)
+-{
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->ndar, addr, 64);
+-}
++ if (g_device) {
++ spin_lock_bh(&g_device->ch_lock);
++ for (i = 0; i < FSL_DMA_CH_NUM; i++) {
++ if (g_device->ch_stat[i]) {
++ spin_unlock_bh(&g_device->ch_lock);
++ return -EBUSY;
++ }
++ }
++ spin_unlock_bh(&g_device->ch_lock);
+
+-static dma_addr_t get_ndar(struct fsl_dma_chan *fsl_chan)
+-{
+- return DMA_IN(fsl_chan, &fsl_chan->reg_base->ndar, 64);
+-}
++ reg = g_device->reg;
+
+-static u32 get_bcr(struct fsl_dma_chan *fsl_chan)
+-{
+- return DMA_IN(fsl_chan, &fsl_chan->reg_base->bcr, 32);
+-}
++ g_device->arbit_mode = mode;
+
+-static int dma_is_idle(struct fsl_dma_chan *fsl_chan)
+-{
+- u32 sr = get_sr(fsl_chan);
+- return (!(sr & FSL_DMA_SR_CB)) || (sr & FSL_DMA_SR_CH);
+-}
++ if (mode & FSL_DMA_GROUP_FIX) { /* Group fixed arbitration */
++ out_be32(®->dmacr,
++ FSL_DMA_GPR3PRI(3) | FSL_DMA_GPR2PRI(2)
++ | FSL_DMA_GPR1PRI(1) | FSL_DMA_GPR0PRI(0));
++ } else { /* Group round robin arbitration */
++ out_be32(®->dmacr, FSL_DMA_DMACR_ERGA_RR);
++ }
+
+-static void dma_start(struct fsl_dma_chan *fsl_chan)
+-{
+- u32 mr_set = 0;;
++ /* Channel round robin arbitration */
++ if (!(mode & FSL_DMA_CH_FIX)) {
++ temp = in_be32(®->dmacr);
++ out_be32(®->dmacr, temp | FSL_DMA_DMACR_ERCA_RR);
++ }
+
+- if (fsl_chan->feature & FSL_DMA_CHAN_PAUSE_EXT) {
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->bcr, 0, 32);
+- mr_set |= FSL_DMA_MR_EMP_EN;
++ return 0;
+ } else
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
+- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32)
+- & ~FSL_DMA_MR_EMP_EN, 32);
+-
+- if (fsl_chan->feature & FSL_DMA_CHAN_START_EXT)
+- mr_set |= FSL_DMA_MR_EMS_EN;
+- else
+- mr_set |= FSL_DMA_MR_CS;
+-
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
+- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32)
+- | mr_set, 32);
++ return -EFAULT;
+ }
+
+-static void dma_halt(struct fsl_dma_chan *fsl_chan)
++static void free_chan(int channel_num)
+ {
+- int i;
+-
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
+- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) | FSL_DMA_MR_CA,
+- 32);
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
+- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) & ~(FSL_DMA_MR_CS
+- | FSL_DMA_MR_EMS_EN | FSL_DMA_MR_CA), 32);
+-
+- for (i = 0; i < 100; i++) {
+- if (dma_is_idle(fsl_chan))
+- break;
+- udelay(10);
+- }
+- if (i >= 100 && !dma_is_idle(fsl_chan))
+- dev_err(fsl_chan->dev, "DMA halt timeout!\n");
++ spin_lock_bh(&g_device->ch_lock);
++ g_device->ch_stat[channel_num] = 0;
++ spin_unlock_bh(&g_device->ch_lock);
+ }
+
+-static void set_ld_eol(struct fsl_dma_chan *fsl_chan,
+- struct fsl_desc_sw *desc)
++int fsl_dma_status(int channel_num)
+ {
+- desc->hw.next_ln_addr = CPU_TO_DMA(fsl_chan,
+- DMA_TO_CPU(fsl_chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL,
+- 64);
+-}
++ fsl_dma_reg *reg;
++ u8 ch;
++ u32 status;
+
+-static void append_ld_queue(struct fsl_dma_chan *fsl_chan,
+- struct fsl_desc_sw *new_desc)
+-{
+- struct fsl_desc_sw *queue_tail = to_fsl_desc(fsl_chan->ld_queue.prev);
++ if (!g_device) {
++ printk("Err: DMA driver has not been initialized yet!\n");
++ return -1;
++ }
+
+- if (list_empty(&fsl_chan->ld_queue))
+- return;
++ reg = g_device->reg;
+
+- /* Link to the new descriptor physical address and
+- * Enable End-of-segment interrupt for
+- * the last link descriptor.
+- * (the previous node's next link descriptor)
+- *
+- * For FSL_DMA_IP_83xx, the snoop enable bit need be set.
+- */
+- queue_tail->hw.next_ln_addr = CPU_TO_DMA(fsl_chan,
+- new_desc->async_tx.phys | FSL_DMA_EOSIE |
+- (((fsl_chan->feature & FSL_DMA_IP_MASK)
+- == FSL_DMA_IP_83XX) ? FSL_DMA_SNEN : 0), 64);
+-}
++ status = in_be32(®->dmaes);
++ if (!(status & FSL_DMA_DMAES_VLD))
++ return 0;
+
+-/**
+- * fsl_chan_set_src_loop_size - Set source address hold transfer size
+- * @fsl_chan : Freescale DMA channel
+- * @size : Address loop size, 0 for disable loop
+- *
+- * The set source address hold transfer size. The source
+- * address hold or loop transfer size is when the DMA transfer
+- * data from source address (SA), if the loop size is 4, the DMA will
+- * read data from SA, SA + 1, SA + 2, SA + 3, then loop back to SA,
+- * SA + 1 ... and so on.
+- */
+-static void fsl_chan_set_src_loop_size(struct fsl_dma_chan *fsl_chan, int size)
+-{
+- switch (size) {
+- case 0:
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
+- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) &
+- (~FSL_DMA_MR_SAHE), 32);
+- break;
+- case 1:
+- case 2:
+- case 4:
+- case 8:
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
+- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) |
+- FSL_DMA_MR_SAHE | (__ilog2(size) << 14),
+- 32);
+- break;
+- }
+-}
++ ch = FSL_DMA_DMAES_ERRCHN(status);
++ printk(KERN_ERR "FSL channel config error: ch%d: ", ch);
+
+-/**
+- * fsl_chan_set_dest_loop_size - Set destination address hold transfer size
+- * @fsl_chan : Freescale DMA channel
+- * @size : Address loop size, 0 for disable loop
+- *
+- * The set destination address hold transfer size. The destination
+- * address hold or loop transfer size is when the DMA transfer
+- * data to destination address (TA), if the loop size is 4, the DMA will
+- * write data to TA, TA + 1, TA + 2, TA + 3, then loop back to TA,
+- * TA + 1 ... and so on.
++ if (status & FSL_DMA_DMAES_GPE)
++ printk(KERN_INFO "GPE\n");
++ if (status & FSL_DMA_DMAES_CPE)
++ printk(KERN_INFO "CPE\n");
++ if (status & FSL_DMA_DMAES_SAE)
++ printk(KERN_INFO "SAE\n");
++ if (status & FSL_DMA_DMAES_SOE)
++ printk(KERN_INFO "SOE\n");
++ if (status & FSL_DMA_DMAES_DAE)
++ printk(KERN_INFO "DAE\n");
++ if (status & FSL_DMA_DMAES_DOE)
++ printk(KERN_INFO "DOE\n");
++ if (status & FSL_DMA_DMAES_NCE)
++ printk(KERN_INFO "NCE\n");
++ if (status & FSL_DMA_DMAES_SGE)
++ printk(KERN_INFO "SGE\n");
++ if (status & FSL_DMA_DMAES_SBE)
++ printk(KERN_INFO "SBE\n");
++ if (status & FSL_DMA_DMAES_DBE)
++ printk(KERN_INFO "DBE\n");
++
++ if (ch == channel_num)
++ out_8(®->dmacerr, channel_num);
++
++ return (ch + 1);
++}
++
++/* This function is generally called by the driver at open time.
++ * The DMA driver would do any initialization steps that is required
++ * to get the channel ready for data transfer.
++ *
++ * @param channel_id a pre-defined id. The peripheral driver would specify
++ * the id associated with its peripheral. This would be
++ * used by the DMA driver to identify the peripheral
++ * requesting DMA and do the necessary setup on the
++ * channel associated with the particular peripheral.
++ * The DMA driver could use static or dynamic DMA channel
++ * allocation.
++ * @return returns a negative number on error if request for a DMA channel
++ * did not succeed, returns the channel number to be used
++ * on success.
+ */
+-static void fsl_chan_set_dest_loop_size(struct fsl_dma_chan *fsl_chan, int size)
++int fsl_dma_chan_request(int channel_id)
+ {
+- switch (size) {
+- case 0:
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
+- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) &
+- (~FSL_DMA_MR_DAHE), 32);
+- break;
+- case 1:
+- case 2:
+- case 4:
+- case 8:
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
+- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) |
+- FSL_DMA_MR_DAHE | (__ilog2(size) << 16),
+- 32);
+- break;
++ struct fsl_device *device = g_device;
++ struct fsl_dma_chan *fsl_chan;
++
++ if (!device) {
++ fsl_init();
++ if (!g_device)
++ return -EINVAL;
++ device = g_device;
+ }
+-}
+
+-/**
+- * fsl_chan_toggle_ext_pause - Toggle channel external pause status
+- * @fsl_chan : Freescale DMA channel
+- * @size : Pause control size, 0 for disable external pause control.
+- * The maximum is 1024.
+- *
+- * The Freescale DMA channel can be controlled by the external
+- * signal DREQ#. The pause control size is how many bytes are allowed
+- * to transfer before pausing the channel, after which a new assertion
+- * of DREQ# resumes channel operation.
+- */
+-static void fsl_chan_toggle_ext_pause(struct fsl_dma_chan *fsl_chan, int size)
+-{
+- if (size > 1024)
+- return;
++ if (channel_id < 0 || channel_id >= FSL_DMA_CH_NUM)
++ return -EINVAL;
+
+- if (size) {
+- DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
+- DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32)
+- | ((__ilog2(size) << 24) & 0x0f000000),
+- 32);
+- fsl_chan->feature |= FSL_DMA_CHAN_PAUSE_EXT;
+- } else
+- fsl_chan->feature &= ~FSL_DMA_CHAN_PAUSE_EXT;
+-}
++ fsl_chan = g_fchan + channel_id;
++ spin_lock_bh(&device->ch_lock);
++ if (device->ch_stat[channel_id] == 0) {
++ device->ch_stat[channel_id] = 1;
++ spin_unlock_bh(&device->ch_lock);
++ sema_init(&fsl_chan->sem_lock, 1);
++ return channel_id;
++ }
++ spin_unlock_bh(&device->ch_lock);
+
+-/**
+- * fsl_chan_toggle_ext_start - Toggle channel external start status
+- * @fsl_chan : Freescale DMA channel
+- * @enable : 0 is disabled, 1 is enabled.
+- *
+- * If enable the external start, the channel can be started by an
+- * external DMA start pin. So the dma_start() does not start the
+- * transfer immediately. The DMA channel will wait for the
+- * control pin asserted.
+- */
+-static void fsl_chan_toggle_ext_start(struct fsl_dma_chan *fsl_chan, int enable)
+-{
+- if (enable)
+- fsl_chan->feature |= FSL_DMA_CHAN_START_EXT;
+- else
+- fsl_chan->feature &= ~FSL_DMA_CHAN_START_EXT;
++ return -EBUSY;
+ }
++EXPORT_SYMBOL(fsl_dma_chan_request);
+
+-static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
++void fsl_dma_free_chan(int channel_num)
+ {
+- struct fsl_desc_sw *desc = tx_to_fsl_desc(tx);
+- struct fsl_dma_chan *fsl_chan = to_fsl_chan(tx->chan);
+- unsigned long flags;
+- dma_cookie_t cookie;
++ struct fsl_dma_chan *fsl_chan = g_fchan + channel_num;
++ fsl_dma_reg *reg = g_device->reg;
+
+- /* cookie increment and adding to ld_queue must be atomic */
+- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
+-
+- cookie = fsl_chan->common.cookie;
+- cookie++;
+- if (cookie < 0)
+- cookie = 1;
+- desc->async_tx.cookie = cookie;
+- fsl_chan->common.cookie = desc->async_tx.cookie;
+-
+- append_ld_queue(fsl_chan, desc);
+- list_splice_init(&desc->async_tx.tx_list, fsl_chan->ld_queue.prev);
++ if (channel_num < 0 || channel_num >= FSL_DMA_CH_NUM)
++ return;
+
+- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
++ DPRINTK("free channel: %d\n", channel_num);
+
+- return cookie;
+-}
++ free_chan(channel_num);
+
+-/**
+- * fsl_dma_alloc_descriptor - Allocate descriptor from channel's DMA pool.
+- * @fsl_chan : Freescale DMA channel
+- *
+- * Return - The descriptor allocated. NULL for failed.
+- */
+-static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
+- struct fsl_dma_chan *fsl_chan)
+-{
+- dma_addr_t pdesc;
+- struct fsl_desc_sw *desc_sw;
++ fsl_dma_memcpy_cleanup(fsl_chan);
+
+- desc_sw = dma_pool_alloc(fsl_chan->desc_pool, GFP_ATOMIC, &pdesc);
+- if (desc_sw) {
+- memset(desc_sw, 0, sizeof(struct fsl_desc_sw));
+- dma_async_tx_descriptor_init(&desc_sw->async_tx,
+- &fsl_chan->common);
+- desc_sw->async_tx.tx_submit = fsl_dma_tx_submit;
+- INIT_LIST_HEAD(&desc_sw->async_tx.tx_list);
+- desc_sw->async_tx.phys = pdesc;
+- }
++ /* Clear enable request */
++ out_8(®->dmacerq, channel_num);
+
+- return desc_sw;
++ /* Clear interrupt, error interrupt and error etc. */
++ out_8(®->dmaceei, channel_num);
++ out_8(®->dmacerr, channel_num);
++ out_8(®->dmacint, channel_num);
+ }
++EXPORT_SYMBOL(fsl_dma_free_chan);
+
+-
+-/**
+- * fsl_dma_alloc_chan_resources - Allocate resources for DMA channel.
+- * @fsl_chan : Freescale DMA channel
+- *
+- * This function will create a dma pool for descriptor allocation.
+- *
+- * Return - The number of descriptors allocated.
+- */
+-static int fsl_dma_alloc_chan_resources(struct dma_chan *chan)
++void fsl_dma_enable(int channel_num)
+ {
+- struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan);
++ fsl_dma_reg *reg = g_device->reg;
++ u32 *ltcd, *mtcd;
++ int j;
+
+- /* Has this channel already been allocated? */
+- if (fsl_chan->desc_pool)
+- return 1;
++ if (channel_num < 0 || channel_num >= FSL_DMA_CH_NUM)
++ return;
+
+- /* We need the descriptor to be aligned to 32bytes
+- * for meeting FSL DMA specification requirement.
+- */
+- fsl_chan->desc_pool = dma_pool_create("fsl_dma_engine_desc_pool",
+- fsl_chan->dev, sizeof(struct fsl_desc_sw),
+- 32, 0);
+- if (!fsl_chan->desc_pool) {
+- dev_err(fsl_chan->dev, "No memory for channel %d "
+- "descriptor dma pool.\n", fsl_chan->id);
+- return 0;
+- }
++ /* Get the address of TCD in local CPU memory space */
++ ltcd = (u32 *) (g_device->tcd + channel_num);
++ mtcd = (u32 *) (g_device->mtcd.addr_va
++ + channel_num * MAX_TCD_NUM_PER_CH);
+
+- return 1;
+-}
++ /* Clear the local TCD area */
++ memset(ltcd, 0, sizeof(TCD));
+
+-/**
+- * fsl_dma_free_chan_resources - Free all resources of the channel.
+- * @fsl_chan : Freescale DMA channel
+- */
+-static void fsl_dma_free_chan_resources(struct dma_chan *chan)
+-{
+- struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan);
+- struct fsl_desc_sw *desc, *_desc;
+- unsigned long flags;
+-
+- dev_dbg(fsl_chan->dev, "Free all channel resources.\n");
+- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
+- list_for_each_entry_safe(desc, _desc, &fsl_chan->ld_queue, node) {
+-#ifdef FSL_DMA_LD_DEBUG
+- dev_dbg(fsl_chan->dev,
+- "LD %p will be released.\n", desc);
+-#endif
+- list_del(&desc->node);
+- /* free link descriptor */
+- dma_pool_free(fsl_chan->desc_pool, desc, desc->async_tx.phys);
++ for (j = 0; j < (sizeof(TCD) / 4); j++) {
++ out_be32(ltcd, *mtcd);
++ ltcd++;
++ mtcd++;
+ }
+- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
+- dma_pool_destroy(fsl_chan->desc_pool);
+
+- fsl_chan->desc_pool = NULL;
++ /* Enable request */
++ out_8(®->dmaserq, channel_num);
++ return;
+ }
++EXPORT_SYMBOL(fsl_dma_enable);
+
+-static struct dma_async_tx_descriptor *
+-fsl_dma_prep_interrupt(struct dma_chan *chan, unsigned long flags)
++void fsl_dma_disable(int channel_num)
+ {
+- struct fsl_dma_chan *fsl_chan;
+- struct fsl_desc_sw *new;
+-
+- if (!chan)
+- return NULL;
+-
+- fsl_chan = to_fsl_chan(chan);
+-
+- new = fsl_dma_alloc_descriptor(fsl_chan);
+- if (!new) {
+- dev_err(fsl_chan->dev, "No free memory for link descriptor\n");
+- return NULL;
+- }
+-
+- new->async_tx.cookie = -EBUSY;
+- new->async_tx.flags = flags;
+-
+- /* Insert the link descriptor to the LD ring */
+- list_add_tail(&new->node, &new->async_tx.tx_list);
++ fsl_dma_reg *reg = g_device->reg;
++ if (channel_num < 0 || channel_num >= FSL_DMA_CH_NUM)
++ return;
+
+- /* Set End-of-link to the last link descriptor of new list*/
+- set_ld_eol(fsl_chan, new);
++ /* Clear enable request */
++ out_8(®->dmacerq, channel_num);
+
+- return &new->async_tx;
++ return;
+ }
+
+-static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
+- struct dma_chan *chan, dma_addr_t dma_dest, dma_addr_t dma_src,
+- size_t len, unsigned long flags)
++static int off_to_size(size_t off)
+ {
+- struct fsl_dma_chan *fsl_chan;
+- struct fsl_desc_sw *first = NULL, *prev = NULL, *new;
+- size_t copy;
+- LIST_HEAD(link_chain);
+-
+- if (!chan)
+- return NULL;
+-
+- if (!len)
+- return NULL;
+-
+- fsl_chan = to_fsl_chan(chan);
+-
+- do {
+-
+- /* Allocate the link descriptor from DMA pool */
+- new = fsl_dma_alloc_descriptor(fsl_chan);
+- if (!new) {
+- dev_err(fsl_chan->dev,
+- "No free memory for link descriptor\n");
+- return NULL;
+- }
+-#ifdef FSL_DMA_LD_DEBUG
+- dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new);
+-#endif
++ int i, temp;
+
+- copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT);
++ /* For PSC FIFO DMA operation
++ * Destination/source address is fixed as the address
++ * of FIFO data register, so no address offset is needed
++ * for this operation, bus size is default 32bit.
++ */
++ if (!off)
++ return 2;
+
+- set_desc_cnt(fsl_chan, &new->hw, copy);
+- set_desc_src(fsl_chan, &new->hw, dma_src);
+- set_desc_dest(fsl_chan, &new->hw, dma_dest);
++ temp = off;
++ for (i = 0; ; i++) {
++ temp = (int)(temp / 2);
++ if (!temp)
++ return i;
++ }
++}
++
++/**
++ * fsl_dma_config - function that initiates a FSL DMA transaction buffers
++ * @channel_num FSL DMA channel number
++ * @dma_buf an array of physical addresses to the user defined
++ * buffers. The caller must guarantee the dma_buf is
++ * available until the transfer is completed.
++ * @num_buf number of buffers in the array
++ * @mode specifies whether this is READ or WRITE operation
++ * @return This function returns a negative number on error if buffer
++ * could not be added with DMA for transfer. On Success, it
++ * returns 0
++ */
++int fsl_dma_config(int channel_num, struct fsl_dma_requestbuf *dma_buf,
++ int num_buf)
++{
++ struct fsl_dma_chan *fsl_chan = g_fchan + channel_num;
++ LIST_HEAD(new_chain);
++ fsl_dma_reg *reg = g_device->reg;
++ int ch = channel_num, i, nbytes, iter;
++ TCD *tcd;
++ dma_addr_t tcd_dma;
++
++ if (channel_num < 0 || channel_num >= FSL_DMA_CH_NUM
++ || num_buf <= 0 || num_buf > MAX_TCD_NUM_PER_CH)
++ return -EINVAL;
++
++ if (fsl_dma_status(channel_num) != DMA_SUCCESS && fsl_chan->num_buf)
++ return -EBUSY;
++
++ if (down_trylock(&fsl_chan->sem_lock))
++ return -EBUSY;
++ tcd = (TCD *) (g_device->tcd + channel_num);
++
++ /* Use so much descriptor for this transmission */
++ fsl_chan->num_buf = num_buf;
++ fsl_chan->ch_index = channel_num;
++
++ /* Enable error interrupt */
++ out_8(®->dmaseei, ch);
++
++ tcd = g_device->mtcd.addr_va + ch * MAX_TCD_NUM_PER_CH;
++ tcd_dma = g_device->mtcd.addr_pa +
++ ch * MAX_TCD_NUM_PER_CH * sizeof(TCD);
++
++ memset(tcd, 0, sizeof(TCD));
++
++ for (i = 0; i < num_buf; i++) {
++ tcd->saddr = dma_buf[i].src;
++ tcd->daddr = dma_buf[i].dest;
++ tcd->soff = dma_buf[i].soff;
++ tcd->doff = dma_buf[i].doff;
++ tcd->ssize = off_to_size(dma_buf[i].soff);
++ tcd->dsize = off_to_size(dma_buf[i].doff);
++ DPRINTK("doff: %d, soff: %d, dsize: %d, ssize: %d\n",
++ tcd->doff, tcd->soff, tcd->dsize, tcd->ssize);
+
+- if (!first)
+- first = new;
++ if (dma_buf[i].soff >= dma_buf[i].doff)
++ nbytes = dma_buf[i].minor_loop * dma_buf[i].soff;
+ else
+- set_desc_next(fsl_chan, &prev->hw, new->async_tx.phys);
+-
+- new->async_tx.cookie = 0;
+- async_tx_ack(&new->async_tx);
++ nbytes = dma_buf[i].minor_loop * dma_buf[i].doff;
+
+- prev = new;
+- len -= copy;
+- dma_src += copy;
+- dma_dest += copy;
+-
+- /* Insert the link descriptor to the LD ring */
+- list_add_tail(&new->node, &first->async_tx.tx_list);
+- } while (len);
+-
+- new->async_tx.flags = flags; /* client is in control of this ack */
+- new->async_tx.cookie = -EBUSY;
+-
+- /* Set End-of-link to the last link descriptor of new list*/
+- set_ld_eol(fsl_chan, new);
+-
+- return first ? &first->async_tx : NULL;
+-}
+-
+-/**
+- * fsl_dma_update_completed_cookie - Update the completed cookie.
+- * @fsl_chan : Freescale DMA channel
+- */
+-static void fsl_dma_update_completed_cookie(struct fsl_dma_chan *fsl_chan)
+-{
+- struct fsl_desc_sw *cur_desc, *desc;
+- dma_addr_t ld_phy;
+-
+- ld_phy = get_cdar(fsl_chan) & FSL_DMA_NLDA_MASK;
+-
+- if (ld_phy) {
+- cur_desc = NULL;
+- list_for_each_entry(desc, &fsl_chan->ld_queue, node)
+- if (desc->async_tx.phys == ld_phy) {
+- cur_desc = desc;
+- break;
+- }
+-
+- if (cur_desc && cur_desc->async_tx.cookie) {
+- if (dma_is_idle(fsl_chan))
+- fsl_chan->completed_cookie =
+- cur_desc->async_tx.cookie;
+- else
+- fsl_chan->completed_cookie =
+- cur_desc->async_tx.cookie - 1;
++ tcd->nbytes = nbytes;
++ tcd->slast = 0;
++ tcd->dlast_sga = 0;
++
++ iter = dma_buf[i].len / nbytes;
++
++ if (tcd->soff && tcd->doff) {
++ tcd->citer_elink = 1;
++ tcd->biter_elink = 1;
++ tcd->citer_linkch = channel_num;
++ if (iter > 0x1ff)
++ panic("iterations won't fit in field");
++ tcd->citer = iter;
++ tcd->biter = iter;
++ tcd->start = 1;
++ } else {
++ /* citer_linkch contains the high bits of iter */
++ tcd->citer_linkch = iter >> 9;
++ tcd->biter_linkch = iter >> 9;
++ tcd->citer = iter & 0x1ff;
++ tcd->biter = iter & 0x1ff;
++ if (i == (num_buf - 1))
++ tcd->d_req = 1;
+ }
+- }
+-}
+
+-/**
+- * fsl_chan_ld_cleanup - Clean up link descriptors
+- * @fsl_chan : Freescale DMA channel
+- *
+- * This function clean up the ld_queue of DMA channel.
+- * If 'in_intr' is set, the function will move the link descriptor to
+- * the recycle list. Otherwise, free it directly.
+- */
+-static void fsl_chan_ld_cleanup(struct fsl_dma_chan *fsl_chan)
+-{
+- struct fsl_desc_sw *desc, *_desc;
+- unsigned long flags;
++ tcd->e_sg = 0;
+
+- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
+-
+- dev_dbg(fsl_chan->dev, "chan completed_cookie = %d\n",
+- fsl_chan->completed_cookie);
+- list_for_each_entry_safe(desc, _desc, &fsl_chan->ld_queue, node) {
+- dma_async_tx_callback callback;
+- void *callback_param;
+-
+- if (dma_async_is_complete(desc->async_tx.cookie,
+- fsl_chan->completed_cookie, fsl_chan->common.cookie)
+- == DMA_IN_PROGRESS)
+- break;
+-
+- callback = desc->async_tx.callback;
+- callback_param = desc->async_tx.callback_param;
+-
+- /* Remove from ld_queue list */
+- list_del(&desc->node);
+-
+- dev_dbg(fsl_chan->dev, "link descriptor %p will be recycle.\n",
+- desc);
+- dma_pool_free(fsl_chan->desc_pool, desc, desc->async_tx.phys);
+-
+- /* Run the link descriptor callback function */
+- if (callback) {
+- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
+- dev_dbg(fsl_chan->dev, "link descriptor %p callback\n",
+- desc);
+- callback(callback_param);
+- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
++ /* For chain mode */
++ if (i != (num_buf - 1)) {
++ tcd->dlast_sga = tcd_dma + (i + 1) * sizeof(TCD);
++ tcd->e_sg = 1;
++ } else {
++ tcd->int_maj = 1;
+ }
++
++ DPRINTK("TCD dlast_sga: 0x%08x\n", tcd->dlast_sga);
++ tcd++;
++ memset(tcd, 0, sizeof(TCD));
+ }
+- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
++ return 0;
+ }
++EXPORT_SYMBOL(fsl_dma_config);
+
+-/**
+- * fsl_chan_xfer_ld_queue - Transfer link descriptors in channel ld_queue.
+- * @fsl_chan : Freescale DMA channel
++/* This function is called only when the channel occurs error
++ * or has completed transaction.
+ */
+-static void fsl_chan_xfer_ld_queue(struct fsl_dma_chan *fsl_chan)
++static void fsl_dma_memcpy_cleanup(struct fsl_dma_chan *chan)
+ {
+- struct list_head *ld_node;
+- dma_addr_t next_dest_addr;
+- unsigned long flags;
+-
+- if (!dma_is_idle(fsl_chan))
+- return;
++ int ch;
+
+- dma_halt(fsl_chan);
++ chan->status = g_device->reg->dmaes;
+
+- /* If there are some link descriptors
+- * not transfered in queue. We need to start it.
+- */
+- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
++ ch = fsl_dma_status(chan->ch_index);
++ if (ch)
++ ch = ch - 1;
+
+- /* Find the first un-transfer desciptor */
+- for (ld_node = fsl_chan->ld_queue.next;
+- (ld_node != &fsl_chan->ld_queue)
+- && (dma_async_is_complete(
+- to_fsl_desc(ld_node)->async_tx.cookie,
+- fsl_chan->completed_cookie,
+- fsl_chan->common.cookie) == DMA_SUCCESS);
+- ld_node = ld_node->next);
+-
+- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
+-
+- if (ld_node != &fsl_chan->ld_queue) {
+- /* Get the ld start address from ld_queue */
+- next_dest_addr = to_fsl_desc(ld_node)->async_tx.phys;
+- dev_dbg(fsl_chan->dev, "xfer LDs staring from %p\n",
+- (void *)next_dest_addr);
+- set_cdar(fsl_chan, next_dest_addr);
+- dma_start(fsl_chan);
+- } else {
+- set_cdar(fsl_chan, 0);
+- set_ndar(fsl_chan, 0);
++ if (ch == chan->ch_index) {
++ DPRINTK("Channel %d halted, chanerr = %x\n", ch, chan->status);
+ }
+ }
+
+-/**
+- * fsl_dma_memcpy_issue_pending - Issue the DMA start command
+- * @fsl_chan : Freescale DMA channel
+- */
+-static void fsl_dma_memcpy_issue_pending(struct dma_chan *chan)
++static void fsl_dma_isr_bh(u32 intst, u32 err, u32 high)
+ {
+- struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan);
+-
+-#ifdef FSL_DMA_LD_DEBUG
+- struct fsl_desc_sw *ld;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&fsl_chan->desc_lock, flags);
+- if (list_empty(&fsl_chan->ld_queue)) {
+- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
+- return;
+- }
+-
+- dev_dbg(fsl_chan->dev, "--memcpy issue--\n");
+- list_for_each_entry(ld, &fsl_chan->ld_queue, node) {
+- int i;
+- dev_dbg(fsl_chan->dev, "Ch %d, LD %08x\n",
+- fsl_chan->id, ld->async_tx.phys);
+- for (i = 0; i < 8; i++)
+- dev_dbg(fsl_chan->dev, "LD offset %d: %08x\n",
+- i, *(((u32 *)&ld->hw) + i));
++ struct fsl_device *device = g_device;
++ struct fsl_dma_chan *fsl_chan;
++ fsl_dma_reg *reg;
++ u32 i, ch_base = 0, ch;
++ u32 error;
++
++ reg = device->reg;
++ if (high)
++ ch_base = 32;
++
++ for (i = 0; i < 32; i++) {
++ error = 0;
++ if (intst & (1 << i)) {
++ if (err & (1 << i))
++ error = in_be32(®->dmaes);
++ ch = i + ch_base;
++ fsl_chan = g_fchan + ch;
++ DPRINTK("channel %d occurs an interrupt\n", ch);
++
++ /* Clear interrupt request */
++ out_8(®->dmacint, ch);
++
++ /* Clear enable error interrupt */
++ out_8(®->dmaceei, ch);
++
++ up(&fsl_chan->sem_lock);
++ if (fsl_chan->cb_fn)
++ fsl_chan->cb_fn(fsl_chan->cb_args, error);
++ }
+ }
+- dev_dbg(fsl_chan->dev, "----------------\n");
+- spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
+-#endif
+-
+- fsl_chan_xfer_ld_queue(fsl_chan);
++ return;
+ }
+-
+-/**
+- * fsl_dma_is_complete - Determine the DMA status
+- * @fsl_chan : Freescale DMA channel
+- */
+-static enum dma_status fsl_dma_is_complete(struct dma_chan *chan,
+- dma_cookie_t cookie,
+- dma_cookie_t *done,
+- dma_cookie_t *used)
++/*
++cys add
++the function used for recorved lost dma irq.
++*/
++int fsl_dma_up_semaphore(unsigned int channel)
+ {
+- struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan);
+- dma_cookie_t last_used;
+- dma_cookie_t last_complete;
+-
+- fsl_chan_ld_cleanup(fsl_chan);
+-
+- last_used = chan->cookie;
+- last_complete = fsl_chan->completed_cookie;
+-
+- if (done)
+- *done = last_complete;
+-
+- if (used)
+- *used = last_used;
+-
+- return dma_async_is_complete(cookie, last_complete, last_used);
++ struct fsl_device *device = g_device;
++ struct fsl_dma_chan *fsl_chan;
++ fsl_chan = g_fchan + channel;
++ up(&fsl_chan->sem_lock);
++ return 0;
+ }
+-
+-static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data)
++EXPORT_SYMBOL(fsl_dma_up_semaphore);
++static irqreturn_t fsl_do_interrupt(int irq, void *data)
+ {
+- struct fsl_dma_chan *fsl_chan = (struct fsl_dma_chan *)data;
+- u32 stat;
+- int update_cookie = 0;
+- int xfer_ld_q = 0;
+-
+- stat = get_sr(fsl_chan);
+- dev_dbg(fsl_chan->dev, "event: channel %d, stat = 0x%x\n",
+- fsl_chan->id, stat);
+- set_sr(fsl_chan, stat); /* Clear the event register */
+-
+- stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH);
+- if (!stat)
+- return IRQ_NONE;
+-
+- if (stat & FSL_DMA_SR_TE)
+- dev_err(fsl_chan->dev, "Transfer Error!\n");
+-
+- /* Programming Error
+- * The DMA_INTERRUPT async_tx is a NULL transfer, which will
+- * triger a PE interrupt.
+- */
+- if (stat & FSL_DMA_SR_PE) {
+- dev_dbg(fsl_chan->dev, "event: Programming Error INT\n");
+- if (get_bcr(fsl_chan) == 0) {
+- /* BCR register is 0, this is a DMA_INTERRUPT async_tx.
+- * Now, update the completed cookie, and continue the
+- * next uncompleted transfer.
+- */
+- update_cookie = 1;
+- xfer_ld_q = 1;
+- }
+- stat &= ~FSL_DMA_SR_PE;
+- }
++ struct fsl_device *device = g_device;
++ fsl_dma_reg *reg;
++ u32 inth, intl, eeih, eeil;
++ u32 errh, errl;
++
++ DPRINTK("receive one interrupt!\n");
++ if (!device)
++ return NO_IRQ;
++ reg = device->reg;
++ inth = in_be32(®->dmainth);
++ intl = in_be32(®->dmaintl);
++ eeih = in_be32(®->dmaeeih);
++ eeil = in_be32(®->dmaeeil);
++
++ errh = in_be32(®->dmaerrh);
++ errl = in_be32(®->dmaerrl);
++
++ inth &= eeih;
++ intl &= eeil;
+
+- /* If the link descriptor segment transfer finishes,
+- * we will recycle the used descriptor.
+- */
+- if (stat & FSL_DMA_SR_EOSI) {
+- dev_dbg(fsl_chan->dev, "event: End-of-segments INT\n");
+- dev_dbg(fsl_chan->dev, "event: clndar %p, nlndar %p\n",
+- (void *)get_cdar(fsl_chan), (void *)get_ndar(fsl_chan));
+- stat &= ~FSL_DMA_SR_EOSI;
+- update_cookie = 1;
+- }
++ DPRINTK("es:0x%08x\n", in_be32(®->dmaes));
+
+- /* For MPC8349, EOCDI event need to update cookie
+- * and start the next transfer if it exist.
+- */
+- if (stat & FSL_DMA_SR_EOCDI) {
+- dev_dbg(fsl_chan->dev, "event: End-of-Chain link INT\n");
+- stat &= ~FSL_DMA_SR_EOCDI;
+- update_cookie = 1;
+- xfer_ld_q = 1;
+- }
++ /* Clear all interrupt request */
++ out_8(®->dmacint, 0x7f);
+
+- /* If it current transfer is the end-of-transfer,
+- * we should clear the Channel Start bit for
+- * prepare next transfer.
+- */
+- if (stat & FSL_DMA_SR_EOLNI) {
+- dev_dbg(fsl_chan->dev, "event: End-of-link INT\n");
+- stat &= ~FSL_DMA_SR_EOLNI;
+- xfer_ld_q = 1;
+- }
++ if (!(inth & eeih) && !(intl & eeil))
++ return IRQ_NONE;
+
+- if (update_cookie)
+- fsl_dma_update_completed_cookie(fsl_chan);
+- if (xfer_ld_q)
+- fsl_chan_xfer_ld_queue(fsl_chan);
+- if (stat)
+- dev_dbg(fsl_chan->dev, "event: unhandled sr 0x%02x\n",
+- stat);
++ fsl_dma_isr_bh(inth, errh, 1);
++ fsl_dma_isr_bh(intl, errl, 0);
+
+- dev_dbg(fsl_chan->dev, "event: Exit\n");
+- tasklet_schedule(&fsl_chan->tasklet);
+ return IRQ_HANDLED;
+ }
+
+-static irqreturn_t fsl_dma_do_interrupt(int irq, void *data)
++int fsl_dma_callback_set(int channel_num, fsl_dma_callback_t callback,
++ void *arg)
+ {
+- struct fsl_dma_device *fdev = (struct fsl_dma_device *)data;
+- u32 gsr;
+- int ch_nr;
++ struct fsl_dma_chan *fsl_chan = g_fchan + channel_num;
+
+- gsr = (fdev->feature & FSL_DMA_BIG_ENDIAN) ? in_be32(fdev->reg_base)
+- : in_le32(fdev->reg_base);
+- ch_nr = (32 - ffs(gsr)) / 8;
++ if (channel_num < 0 || channel_num >= FSL_DMA_CH_NUM)
++ return -EINVAL;
+
+- return fdev->chan[ch_nr] ? fsl_dma_chan_do_interrupt(irq,
+- fdev->chan[ch_nr]) : IRQ_NONE;
+-}
++ if (fsl_dma_status(channel_num) == DMA_IN_PROGRESS)
++ return -EBUSY;
+
+-static void dma_do_tasklet(unsigned long data)
+-{
+- struct fsl_dma_chan *fsl_chan = (struct fsl_dma_chan *)data;
+- fsl_chan_ld_cleanup(fsl_chan);
++ fsl_chan->cb_fn = callback;
++ fsl_chan->cb_args = arg;
++
++ return 0;
+ }
++EXPORT_SYMBOL(fsl_dma_callback_set);
+
+-static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev,
+- struct device_node *node, u32 feature, const char *compatible)
++/*
++ * Perform a FSL transaction to verify the HW works.
++ */
++#define FSL_TEST_SIZE 0x200
++
++static int fsl_self_test(struct fsl_device *device)
+ {
+- struct fsl_dma_chan *new_fsl_chan;
+- int err;
++ struct fsl_dma_requestbuf buf[3];
++ u8 *src0, *dest0;
++ u8 *src1, *dest1;
++ u8 *src2, *dest2;
++ dma_addr_t sphyaddr0, dphyaddr0;
++ dma_addr_t sphyaddr1, dphyaddr1;
++ dma_addr_t sphyaddr2, dphyaddr2;
++ int ch;
++ dma_cookie_t cookie;
++ int i, err = 0;
+
+- /* alloc channel */
+- new_fsl_chan = kzalloc(sizeof(struct fsl_dma_chan), GFP_KERNEL);
+- if (!new_fsl_chan) {
+- dev_err(fdev->dev, "No free memory for allocating "
+- "dma channels!\n");
++ src0 = dma_alloc_coherent(NULL, sizeof(u8) * FSL_TEST_SIZE,
++ &sphyaddr0, GFP_KERNEL);
++ src1 = dma_alloc_coherent(NULL, sizeof(u8) * FSL_TEST_SIZE,
++ &sphyaddr1, GFP_KERNEL);
++ src2 = dma_alloc_coherent(NULL, sizeof(u8) * FSL_TEST_SIZE,
++ &sphyaddr2, GFP_KERNEL);
++ if (!src0 || !src1 || !src2)
+ return -ENOMEM;
+- }
+-
+- /* get dma channel register base */
+- err = of_address_to_resource(node, 0, &new_fsl_chan->reg);
+- if (err) {
+- dev_err(fdev->dev, "Can't get %s property 'reg'\n",
+- node->full_name);
+- goto err_no_reg;
+- }
+-
+- new_fsl_chan->feature = feature;
+-
+- if (!fdev->feature)
+- fdev->feature = new_fsl_chan->feature;
+-
+- /* If the DMA device's feature is different than its channels',
+- * report the bug.
+- */
+- WARN_ON(fdev->feature != new_fsl_chan->feature);
+
+- new_fsl_chan->dev = fdev->dev;
+- new_fsl_chan->reg_base = ioremap(new_fsl_chan->reg.start,
+- new_fsl_chan->reg.end - new_fsl_chan->reg.start + 1);
+-
+- new_fsl_chan->id = ((new_fsl_chan->reg.start - 0x100) & 0xfff) >> 7;
+- if (new_fsl_chan->id > FSL_DMA_MAX_CHANS_PER_DEVICE) {
+- dev_err(fdev->dev, "There is no %d channel!\n",
+- new_fsl_chan->id);
+- err = -EINVAL;
+- goto err_no_chan;
+- }
+- fdev->chan[new_fsl_chan->id] = new_fsl_chan;
+- tasklet_init(&new_fsl_chan->tasklet, dma_do_tasklet,
+- (unsigned long)new_fsl_chan);
+-
+- /* Init the channel */
+- dma_init(new_fsl_chan);
+-
+- /* Clear cdar registers */
+- set_cdar(new_fsl_chan, 0);
+-
+- switch (new_fsl_chan->feature & FSL_DMA_IP_MASK) {
+- case FSL_DMA_IP_85XX:
+- new_fsl_chan->toggle_ext_start = fsl_chan_toggle_ext_start;
+- new_fsl_chan->toggle_ext_pause = fsl_chan_toggle_ext_pause;
+- case FSL_DMA_IP_83XX:
+- new_fsl_chan->set_src_loop_size = fsl_chan_set_src_loop_size;
+- new_fsl_chan->set_dest_loop_size = fsl_chan_set_dest_loop_size;
++ dest0 = dma_alloc_coherent(NULL, sizeof(u8) * FSL_TEST_SIZE,
++ &dphyaddr0, GFP_KERNEL);
++ dest1 = dma_alloc_coherent(NULL, sizeof(u8) * FSL_TEST_SIZE,
++ &dphyaddr1, GFP_KERNEL);
++ dest2 = dma_alloc_coherent(NULL, sizeof(u8) * FSL_TEST_SIZE,
++ &dphyaddr2, GFP_KERNEL);
++ if (!dest0 || !dest1 || !dest2) {
++ dma_free_coherent(NULL, sizeof(u8) * FSL_TEST_SIZE, src0,
++ sphyaddr0);
++ dma_free_coherent(NULL, sizeof(u8) * FSL_TEST_SIZE, src1,
++ sphyaddr1);
++ return -ENOMEM;
+ }
+
+- spin_lock_init(&new_fsl_chan->desc_lock);
+- INIT_LIST_HEAD(&new_fsl_chan->ld_queue);
+-
+- new_fsl_chan->common.device = &fdev->common;
+-
+- /* Add the channel to DMA device channel list */
+- list_add_tail(&new_fsl_chan->common.device_node,
+- &fdev->common.channels);
+- fdev->common.chancnt++;
+-
+- new_fsl_chan->irq = irq_of_parse_and_map(node, 0);
+- if (new_fsl_chan->irq != NO_IRQ) {
+- err = request_irq(new_fsl_chan->irq,
+- &fsl_dma_chan_do_interrupt, IRQF_SHARED,
+- "fsldma-channel", new_fsl_chan);
+- if (err) {
+- dev_err(fdev->dev, "DMA channel %s request_irq error "
+- "with return %d\n", node->full_name, err);
+- goto err_no_irq;
+- }
++ memset(dest0, 0, FSL_TEST_SIZE);
++ memset(dest1, 0, FSL_TEST_SIZE);
++ memset(dest2, 0, FSL_TEST_SIZE);
++
++ /* Fill in src buffer */
++ for (i = 0; i < FSL_TEST_SIZE; i++) {
++ src0[i] = (u8) i;
++ src1[i] = (u8) i;
++ src2[i] = (u8) i;
++ }
++
++ /* Set arbitration mode chj */
++ fsl_dma_cfg_arbit_mode(FSL_DMA_GROUP_FIX | FSL_DMA_CH_FIX);
++
++ /* Search for one available dma channel */
++ ch = fsl_dma_chan_request(32);
++ if (ch < 0) {
++ err = -ENODEV;
++ goto out;
++ }
++
++ /* Both source and destination port size: 32 bits */
++ buf[0].src = sphyaddr0;
++ buf[0].dest = dphyaddr0;
++ buf[0].soff = 4;
++ buf[0].doff = 1;
++ buf[0].len = FSL_TEST_SIZE;
++ buf[0].minor_loop = 8; /* Minor bytes: 32 */
++
++ buf[1].src = sphyaddr1;
++ buf[1].dest = dphyaddr1;
++ buf[1].soff = 4;
++ buf[1].doff = 1;
++ buf[1].len = FSL_TEST_SIZE;
++ buf[1].minor_loop = 8; /* Minor bytes: 32 */
++
++ buf[2].src = sphyaddr2;
++ buf[2].dest = dphyaddr2;
++ buf[2].soff = 4;
++ buf[2].doff = 1;
++ buf[2].len = FSL_TEST_SIZE;
++ buf[2].minor_loop = 8; /* Minor bytes: 32 */
++
++ cookie = fsl_dma_config(ch, &buf[0], 3);
++ fsl_dma_enable(ch);
++ msleep(100);
++
++ if (fsl_dma_status(ch) != DMA_SUCCESS) {
++ printk(KERN_ERR
++ "fsldma: Self-test copy timed out, disabling\n");
++ err = -ENODEV;
++ goto free_resources;
++ }
++ if (memcmp(src0, dest0, FSL_TEST_SIZE) ||
++ memcmp(src1, dest1, FSL_TEST_SIZE) ||
++ memcmp(src2, dest2, FSL_TEST_SIZE)) {
++ printk(KERN_ERR
++ "fsldma: Self-test copy failed compare, disabling\n");
++ err = -ENODEV;
++ fsl_dma_status(ch);
++ goto free_resources;
++ } else {
++ printk("fsldma: Self-test copy successfully\n");
+ }
+
+- dev_info(fdev->dev, "#%d (%s), irq %d\n", new_fsl_chan->id,
+- compatible,
+- new_fsl_chan->irq != NO_IRQ ? new_fsl_chan->irq : fdev->irq);
+-
+- return 0;
+-
+-err_no_irq:
+- list_del(&new_fsl_chan->common.device_node);
+-err_no_chan:
+- iounmap(new_fsl_chan->reg_base);
+-err_no_reg:
+- kfree(new_fsl_chan);
++free_resources:
++ fsl_dma_free_chan(ch);
++out:
++ dma_free_coherent(NULL, FSL_TEST_SIZE, src0, sphyaddr0);
++ dma_free_coherent(NULL, FSL_TEST_SIZE, dest0, dphyaddr0);
++ dma_free_coherent(NULL, FSL_TEST_SIZE, src1, sphyaddr1);
++ dma_free_coherent(NULL, FSL_TEST_SIZE, dest1, dphyaddr1);
+ return err;
+ }
+
+-static void fsl_dma_chan_remove(struct fsl_dma_chan *fchan)
+-{
+- if (fchan->irq != NO_IRQ)
+- free_irq(fchan->irq, fchan);
+- list_del(&fchan->common.device_node);
+- iounmap(fchan->reg_base);
+- kfree(fchan);
+-}
+-
+-static int __devinit of_fsl_dma_probe(struct of_device *dev,
+- const struct of_device_id *match)
++static int __devinit fsl_init(void)
+ {
+ int err;
+- struct fsl_dma_device *fdev;
+- struct device_node *child;
++ unsigned long base_addr;
++ fsl_dma_reg *reg;
++ TCD *tcd;
++ struct fsl_device *device;
++ struct device_node *np;
++ struct resource r;
++ u32 mask, offset;
+
+- fdev = kzalloc(sizeof(struct fsl_dma_device), GFP_KERNEL);
+- if (!fdev) {
+- dev_err(&dev->dev, "No enough memory for 'priv'\n");
+- return -ENOMEM;
+- }
+- fdev->dev = &dev->dev;
+- INIT_LIST_HEAD(&fdev->common.channels);
+-
+- /* get DMA controller register base */
+- err = of_address_to_resource(dev->node, 0, &fdev->reg);
+- if (err) {
+- dev_err(&dev->dev, "Can't get %s property 'reg'\n",
+- dev->node->full_name);
+- goto err_no_reg;
+- }
+-
+- dev_info(&dev->dev, "Probe the Freescale DMA driver for %s "
+- "controller at %p...\n",
+- match->compatible, (void *)fdev->reg.start);
+- fdev->reg_base = ioremap(fdev->reg.start, fdev->reg.end
+- - fdev->reg.start + 1);
+-
+- dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
+- dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
+- fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources;
+- fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources;
+- fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt;
+- fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy;
+- fdev->common.device_is_tx_complete = fsl_dma_is_complete;
+- fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
+- fdev->common.dev = &dev->dev;
+-
+- fdev->irq = irq_of_parse_and_map(dev->node, 0);
+- if (fdev->irq != NO_IRQ) {
+- err = request_irq(fdev->irq, &fsl_dma_do_interrupt, IRQF_SHARED,
+- "fsldma-device", fdev);
+- if (err) {
+- dev_err(&dev->dev, "DMA device request_irq error "
+- "with return %d\n", err);
+- goto err;
+- }
+- }
++ if (g_device)
++ return 0;
+
+- dev_set_drvdata(&(dev->dev), fdev);
++ /* Map the virtual IRQ number from device tree */
++ np = of_find_compatible_node(NULL, NULL, "mpc512x-dma2");
++ if (!np) {
++ printk(KERN_ERR "Err: no 'mpc512x-dma2' in device tree!\n");
++ return -EINVAL;
++ }
++
++ /* DMA register space */
++ of_address_to_resource(np, 0, &r);
++ of_node_put(np);
++ DPRINTK("DMA engine register address: 0x%08x\n", r.start);
++ reg = (fsl_dma_reg *) ioremap(r.start, sizeof(fsl_dma_reg));
++ if (!reg) {
++ err = -ENOMEM;
++ goto err_regioremap;
++ }
++
++ /* DMA transfer control desciptor area */
++ base_addr = r.start + FSL_DMA_TCD_OFFSET;
++ DPRINTK("Local TCD start address: 0x%08x\n", (u32) base_addr);
++ tcd = (TCD *) ioremap(base_addr, sizeof(TCD) * FSL_DMA_CH_NUM);
++ if (!tcd) {
++ err = -ENOMEM;
++ goto err_tcdioremap;
++ }
++
++ device = kzalloc(sizeof(*device), GFP_KERNEL);
++ if (!device) {
++ err = -ENOMEM;
++ goto err_kzalloc;
++ }
++
++ device->irq = irq_of_parse_and_map(np, 0);
++ of_node_put(np);
++
++ err = request_irq(device->irq, &fsl_do_interrupt,
++ IRQF_SHARED, "mpc5121dma", device);
++ if (err)
++ goto err_irq;
++
++ spin_lock_init(&device->ch_lock);
++ device->reg = reg;
++ device->tcd = tcd;
++ g_device = device;
++
++ /* Allocate buffer for TCDs in memory */
++ device->mtcd.size = (MAX_TCD_NUM_PER_CH * FSL_DMA_CH_NUM + 1)
++ * sizeof(TCD);
++ device->mtcd.addr_v =
++ (TCD *) dma_alloc_coherent(NULL, device->mtcd.size,
++ &device->mtcd.addr_p, GFP_KERNEL);
++ mask = sizeof(TCD) - 1;
++ offset = device->mtcd.addr_p & mask;
++ device->mtcd.addr_va = device->mtcd.addr_v;
++ device->mtcd.addr_pa = device->mtcd.addr_p;
++ if (offset) {
++ offset = sizeof(TCD) - offset;
++ device->mtcd.addr_pa = device->mtcd.addr_p + offset;
++ device->mtcd.addr_va = (TCD *) ((u32) device->mtcd.addr_v
++ + offset);
++ DPRINTK("Note: TCD buffer address is re-aligned:"
++ " offset: 0x%x\n", offset);
++ }
++ DPRINTK("tcd buf phy addr: 0x%08x\n", device->mtcd.addr_pa);
++
++ alloc_dma_channels(device);
++ printk(KERN_INFO "Freescale(R) MPC5121 DMA Engine found, %d channels\n",
++ FSL_DMA_CH_NUM);
++
++ err = fsl_self_test(device);
++ if (err)
++ goto err_self_test;
+
+- /* We cannot use of_platform_bus_probe() because there is no
+- * of_platform_bus_remove. Instead, we manually instantiate every DMA
+- * channel object.
+- */
+- for_each_child_of_node(dev->node, child) {
+- if (of_device_is_compatible(child, "fsl,eloplus-dma-channel"))
+- fsl_dma_chan_probe(fdev, child,
+- FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN,
+- "fsl,eloplus-dma-channel");
+- if (of_device_is_compatible(child, "fsl,elo-dma-channel"))
+- fsl_dma_chan_probe(fdev, child,
+- FSL_DMA_IP_83XX | FSL_DMA_LITTLE_ENDIAN,
+- "fsl,elo-dma-channel");
+- }
+-
+- dma_async_device_register(&fdev->common);
+ return 0;
+
+-err:
+- iounmap(fdev->reg_base);
+-err_no_reg:
+- kfree(fdev);
++err_irq:
++err_kzalloc:
++err_self_test:
++ kfree(device);
++ dma_free_coherent(NULL, device->mtcd.size,
++ device->mtcd.addr_v, device->mtcd.addr_p);
++err_tcdioremap:
++ iounmap(tcd);
++err_regioremap:
++ iounmap(reg);
+ return err;
+ }
+
+-static int of_fsl_dma_remove(struct of_device *of_dev)
++static void __devexit fsl_remove(void)
+ {
+- struct fsl_dma_device *fdev;
+- unsigned int i;
+-
+- fdev = dev_get_drvdata(&of_dev->dev);
+-
+- dma_async_device_unregister(&fdev->common);
++ struct fsl_device *device;
+
+- for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++)
+- if (fdev->chan[i])
+- fsl_dma_chan_remove(fdev->chan[i]);
+-
+- if (fdev->irq != NO_IRQ)
+- free_irq(fdev->irq, fdev);
+-
+- iounmap(fdev->reg_base);
++ if (!g_device)
++ return;
++ device = g_device;
+
+- kfree(fdev);
+- dev_set_drvdata(&of_dev->dev, NULL);
++ free_irq(device->irq, device);
++ iounmap(device->reg);
++ iounmap(device->tcd);
++ dma_free_coherent(NULL, device->mtcd.size,
++ device->mtcd.addr_v, device->mtcd.addr_p);
++ kfree(device);
++}
+
++static int __devinit of_fsl_dma_probe(struct of_device *op, const struct of_device_id *match)
++{
++ fsl_init();
+ return 0;
+ }
+
+-static struct of_device_id of_fsl_dma_ids[] = {
+- { .compatible = "fsl,eloplus-dma", },
+- { .compatible = "fsl,elo-dma", },
++static void of_fsl_dma_remove(struct of_device *op)
++{
++ fsl_remove();
++}
++
++
++static struct of_device_id of_fsl_dma_ids[] = {
++ { .compatible = "mpc512x-dma2", },
+ {}
+ };
+
+ static struct of_platform_driver of_fsl_dma_driver = {
+- .name = "fsl-elo-dma",
++ .name = "fsl-mpc5121e-dma",
+ .match_table = of_fsl_dma_ids,
+ .probe = of_fsl_dma_probe,
+ .remove = of_fsl_dma_remove,
+ };
+-
+ static __init int of_fsl_dma_init(void)
+ {
+ int ret;
+diff -Naur linux-2.6.29/drivers/i2c/busses/i2c-mpc.c linux-2.6.29-v2010041601/drivers/i2c/busses/i2c-mpc.c
+--- linux-2.6.29/drivers/i2c/busses/i2c-mpc.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/i2c/busses/i2c-mpc.c 2010-04-13 20:23:26.000000000 +0200
+@@ -313,7 +313,12 @@
+ .algo = &mpc_algo,
+ .timeout = 1,
+ };
+-
++#if CONFIG_MPC5121_ADS
++static u32 g_i2c_ioctrol[][2]={
++{0x8000a1d8,0x8000a1dc},
++{0x8000a1e0,0x8000a1e4},
++};
++#endif
+ static int __devinit fsl_i2c_probe(struct of_device *op, const struct of_device_id *match)
+ {
+ int result = 0;
+@@ -356,6 +361,27 @@
+ i2c->adap = mpc_ops;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &op->dev;
++#if CONFIG_MPC5121_ADS
++ {
++ unsigned int *val;
++ u32 __iomem *base;
++ val=of_get_property(op->node, "cell-index", NULL);
++ if(*val<2)
++ {
++
++ base=ioremap(g_i2c_ioctrol[*val][0], sizeof(u32));
++ *base=0x00;
++ iounmap(base);
++ base=ioremap(g_i2c_ioctrol[*val][1], sizeof(u32));
++ *base=0x00;
++ iounmap(base);
++ printk("Detected i2c host %d \n",*val);
++ }
++
++
++
++ }
++#endif
+
+ result = i2c_add_adapter(&i2c->adap);
+ if (result < 0) {
+diff -Naur linux-2.6.29/drivers/ide/ide-dma.c linux-2.6.29-v2010041601/drivers/ide/ide-dma.c
+--- linux-2.6.29/drivers/ide/ide-dma.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/ide/ide-dma.c 2010-04-13 20:23:26.000000000 +0200
+@@ -254,10 +254,12 @@
+ /*
+ * avoid false cable warning from eighty_ninty_three()
+ */
++#ifndef CONFIG_PPC_MPC512x
+ if (req_mode > XFER_UDMA_2) {
+ if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
+ mask &= 0x07;
+ }
++#endif
+ break;
+ case XFER_MW_DMA_0:
+ if ((id[ATA_ID_FIELD_VALID] & 2) == 0)
+diff -Naur linux-2.6.29/drivers/ide/Kconfig linux-2.6.29-v2010041601/drivers/ide/Kconfig
+--- linux-2.6.29/drivers/ide/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/ide/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -278,6 +278,14 @@
+ <file:Documentation/ide/ide.txt>. If you have a CMD640 IDE interface
+ and your BIOS does not already do this for you, then say Y here.
+ Otherwise say N.
++config BLK_DEV_MPC512x_IDE
++ tristate "MPC512x IDE support"
++ depends on PPC_MPC512x
++ select BLK_DEV_IDEDMA_PCI
++ help
++ This option provides support for IDE on Freescale MPC512x Systems.
++
++ If unsure, say N.
+
+ config BLK_DEV_IDEPNP
+ tristate "PNP EIDE support"
+@@ -914,6 +922,6 @@
+
+ config BLK_DEV_IDEDMA
+ def_bool BLK_DEV_IDEDMA_SFF || \
+- BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
++ BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA||BLK_DEV_MPC512x_IDE
+
+ endif # IDE
+diff -Naur linux-2.6.29/drivers/ide/Makefile linux-2.6.29-v2010041601/drivers/ide/Makefile
+--- linux-2.6.29/drivers/ide/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/ide/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -117,3 +117,4 @@
+ obj-$(CONFIG_BLK_DEV_IDE_TX4938) += tx4938ide.o
+ obj-$(CONFIG_BLK_DEV_IDE_TX4939) += tx4939ide.o
+ obj-$(CONFIG_BLK_DEV_IDE_AT91) += at91_ide.o
++obj-$(CONFIG_BLK_DEV_MPC512x_IDE) += ppc/
+diff -Naur linux-2.6.29/drivers/ide/ppc/Makefile linux-2.6.29-v2010041601/drivers/ide/ppc/Makefile
+--- linux-2.6.29/drivers/ide/ppc/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/ide/ppc/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,4 @@
++
++obj-$(CONFIG_BLK_DEV_MPC512x_IDE) += mpc512x_ide.o
++
++EXTRA_CFLAGS := -Idrivers/ide
+diff -Naur linux-2.6.29/drivers/ide/ppc/mpc512x.h linux-2.6.29-v2010041601/drivers/ide/ppc/mpc512x.h
+--- linux-2.6.29/drivers/ide/ppc/mpc512x.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/ide/ppc/mpc512x.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,185 @@
++/*
++ * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef _FSL_ATA_H_
++#define _FSL_ATA_H_
++
++/*!
++ * @defgroup ATA ATA/IDE Driver
++ */
++
++/*!
++ * @file mpc512x_ide.h
++ *
++ * @brief MPC512X ATA/IDE hardware register and bit definitions.
++ *
++ * @ingroup ATA
++ */
++#include <asm/fsldma.h>
++#include <asm/fsldma_reg.h>
++
++
++#define HWIF(drive) ((ide_hwif_t *)((drive)->hwif))
++#define HWGROUP(drive) ((ide_hwgroup_t *)(HWIF(drive)->hwgroup))
++
++#define ATA_BASE_ADDR (priv->ata_regs)
++#define IO_ADDRESS(addr) (addr)
++
++#define FSL_ATA_IO IO_ADDRESS((ATA_BASE_ADDR + 0xA0))
++#define FSL_ATA_CTL IO_ADDRESS((ATA_BASE_ADDR + 0xD8))
++
++/*
++ * Interface control registers
++ */
++
++#define FSL_ATA_FIFO_DATA_32 IO_ADDRESS((ATA_BASE_ADDR + 0x18))
++#define FSL_ATA_FIFO_DATA_16 IO_ADDRESS((ATA_BASE_ADDR + 0x1C))
++#define FSL_ATA_FIFO_FILL IO_ADDRESS((ATA_BASE_ADDR + 0x20))
++#define FSL_ATA_CONTROL IO_ADDRESS((ATA_BASE_ADDR + 0x24))
++#define FSL_ATA_INTR_PENDING IO_ADDRESS((ATA_BASE_ADDR + 0x28))
++#define FSL_ATA_INTR_ENABLE IO_ADDRESS((ATA_BASE_ADDR + 0x2C))
++#define FSL_ATA_INTR_CLEAR IO_ADDRESS((ATA_BASE_ADDR + 0x30))
++#define FSL_ATA_FIFO_ALARM IO_ADDRESS((ATA_BASE_ADDR + 0x34))
++
++/*
++ * Control register bit definitions
++ */
++
++#define FSL_ATA_CTRL_FIFO_RST_B 0x80
++#define FSL_ATA_CTRL_ATA_RST_B 0x40
++#define FSL_ATA_CTRL_FIFO_TX_EN 0x20
++#define FSL_ATA_CTRL_FIFO_RCV_EN 0x10
++#define FSL_ATA_CTRL_DMA_PENDING 0x08
++#define FSL_ATA_CTRL_DMA_ULTRA 0x04
++#define FSL_ATA_CTRL_DMA_WRITE 0x02
++#define FSL_ATA_CTRL_IORDY_EN 0x01
++
++/*
++ * Interrupt registers bit definitions
++ */
++
++#define FSL_ATA_INTR_ATA_INTRQ1 0x80
++#define FSL_ATA_INTR_FIFO_UNDERFLOW 0x40
++#define FSL_ATA_INTR_FIFO_OVERFLOW 0x20
++#define FSL_ATA_INTR_CTRL_IDLE 0x10
++#define FSL_ATA_INTR_ATA_INTRQ2 0x08
++
++/*
++ * timing registers
++ */
++
++#define FSL_ATA_TIME_OFF IO_ADDRESS((ATA_BASE_ADDR + 0x00))
++#define FSL_ATA_TIME_ON IO_ADDRESS((ATA_BASE_ADDR + 0x01))
++#define FSL_ATA_TIME_1 IO_ADDRESS((ATA_BASE_ADDR + 0x02))
++#define FSL_ATA_TIME_2w IO_ADDRESS((ATA_BASE_ADDR + 0x03))
++
++#define FSL_ATA_TIME_2r IO_ADDRESS((ATA_BASE_ADDR + 0x04))
++#define FSL_ATA_TIME_AX IO_ADDRESS((ATA_BASE_ADDR + 0x05))
++#define FSL_ATA_TIME_PIO_RDX IO_ADDRESS((ATA_BASE_ADDR + 0x06))
++#define FSL_ATA_TIME_4 IO_ADDRESS((ATA_BASE_ADDR + 0x07))
++
++#define FSL_ATA_TIME_9 IO_ADDRESS((ATA_BASE_ADDR + 0x08))
++#define FSL_ATA_TIME_M IO_ADDRESS((ATA_BASE_ADDR + 0x09))
++#define FSL_ATA_TIME_JN IO_ADDRESS((ATA_BASE_ADDR + 0x0A))
++#define FSL_ATA_TIME_D IO_ADDRESS((ATA_BASE_ADDR + 0x0B))
++
++#define FSL_ATA_TIME_K IO_ADDRESS((ATA_BASE_ADDR + 0x0C))
++#define FSL_ATA_TIME_ACK IO_ADDRESS((ATA_BASE_ADDR + 0x0D))
++#define FSL_ATA_TIME_ENV IO_ADDRESS((ATA_BASE_ADDR + 0x0E))
++#define FSL_ATA_TIME_RPX IO_ADDRESS((ATA_BASE_ADDR + 0x0F))
++
++#define FSL_ATA_TIME_ZAH IO_ADDRESS((ATA_BASE_ADDR + 0x10))
++#define FSL_ATA_TIME_MLIX IO_ADDRESS((ATA_BASE_ADDR + 0x11))
++#define FSL_ATA_TIME_DVH IO_ADDRESS((ATA_BASE_ADDR + 0x12))
++#define FSL_ATA_TIME_DZFS IO_ADDRESS((ATA_BASE_ADDR + 0x13))
++
++#define FSL_ATA_TIME_DVS IO_ADDRESS((ATA_BASE_ADDR + 0x14))
++#define FSL_ATA_TIME_CVH IO_ADDRESS((ATA_BASE_ADDR + 0x15))
++#define FSL_ATA_TIME_SS IO_ADDRESS((ATA_BASE_ADDR + 0x16))
++#define FSL_ATA_TIME_CYC IO_ADDRESS((ATA_BASE_ADDR + 0x17))
++
++/*
++ * other facts
++ */
++#define FSL_ATA_DMA_WATERMARK 32 /* XXX fixme */
++#if (FSL_ATA_DMA_WATERMARK<=32)
++#define FSL_ATA_DMA_MEM_XFER_SIZE 4
++#else
++#define FSL_ATA_DMA_MEM_XFER_SIZE 32
++#endif
++
++#define MPC512X_DMA_ATA_RX 27 /* XXX fixme */
++#define MPC512X_DMA_ATA_TX 28 /* XXX fixme */
++
++#define FSL_DMA_DONE 0 /* XXX fixme */
++#define FSL_DMA_REQUEST_TIMEOUT 1 /* XXX fixme */
++#define FSL_DMA_TRANSFER_ERROR 2 /* XXX fixme */
++
++#define FSL_DMA_MODE_READ 0 /* XXX fixme */
++#define FSL_DMA_MODE_WRITE 1 /* XXX fixme */
++
++#define FSL_ATA_DMA_BD_SIZE_MAX 0xFC00 /* max size of scatterlist segment */
++
++/*! Private data for the drive structure. */
++struct fsl_ata_priv {
++ struct device *dev; /*!< The device */
++ int dma_read_chan; /*!< DMA channel sdma api gave us for reads */
++ int dma_write_chan; /*!< DMA channel sdma api gave us for writes */
++ int ultra; /*!< Remember when we're in ultra mode */
++ int dma_stat; /*!< the state of DMA request */
++ u8 enable; /*!< Current hardware interrupt mask */
++ void *ata_regs; /*!< Base of ata registers */
++ dma_addr_t dma_addr; /* physical address for dma rd/wr */
++
++ int ata_irq; /*!< ATA irq number */
++
++ struct fsl_dma_requestbuf
++ dma_reqbufs[MAX_TCD_NUM_PER_CH];
++
++ struct clk *ata_clk; /*!< rate/pm clk */
++ struct ide_host *host;
++ unsigned int iswrite;
++ spinlock_t lock;
++ /*struct device hw_dev;*/
++};
++
++/*! ATA transfer mode for set_ata_bus_timing() */
++enum ata_mode {
++ PIO, /*!< Specifies PIO mode */
++ MDMA, /*!< Specifies MDMA mode */
++ UDMA /*!< Specifies UDMA mode */
++};
++
++#define INTRQ_MCU 0 /* Enable ATA_INTRQ on the CPU */
++#define INTRQ_DMA 1 /* Enable ATA_INTRQ on the DMA engine */
++
++/*!
++ * This structure defines the bits in the ATA TIME_CONFIGx
++ */
++union fsl_ata_time_cfg {
++ unsigned long config;
++ struct {
++ unsigned char field4;
++ unsigned char field3;
++ unsigned char field2;
++ unsigned char field1;
++ } bytes;
++};
++
++/*!defines the macro for accessing the register */
++#define ATA_RAW_WRITE(v, addr) writel(v, addr)
++#define ATA_RAW_READ(addr) readl(addr)
++/*! Get the configuration of TIME_CONFIG0 */
++#define GET_TIME_CFG(t, base) ((t)->config = ATA_RAW_READ(base))
++
++/*! Set the configuration of TIME_CONFIG0.
++ * And mask is ignored. base is the start address of this configuration.
++ */
++#define SET_TIME_CFG(t, mask, base) (ATA_RAW_WRITE((t)->config, base))
++#endif /* !_FSL_ATA_H_ */
+diff -Naur linux-2.6.29/drivers/input/evdev.c linux-2.6.29-v2010041601/drivers/input/evdev.c
+--- linux-2.6.29/drivers/input/evdev.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/input/evdev.c 2010-04-13 20:23:26.000000000 +0200
+@@ -792,10 +792,24 @@
+ int minor;
+ int error;
+
++
+ for (minor = 0; minor < EVDEV_MINORS; minor++)
++ {
++ if(!minor)
++ {
++ if(test_bit(EV_ABS,dev->evbit)&&test_bit(ABS_PRESSURE,dev->absbit))
++ {
++ break;
++ }
++ else
++ {
++ continue;
++ }
++ }
++
+ if (!evdev_table[minor])
+ break;
+-
++ }
+ if (minor == EVDEV_MINORS) {
+ printk(KERN_ERR "evdev: no more free evdev devices\n");
+ return -ENFILE;
+diff -Naur linux-2.6.29/drivers/input/keyboard/Kconfig linux-2.6.29-v2010041601/drivers/input/keyboard/Kconfig
+--- linux-2.6.29/drivers/input/keyboard/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/input/keyboard/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -277,6 +277,12 @@
+ To compile this driver as a module, choose M here: the
+ module will be called pxa930_rotary.
+
++config KEYBOARD_PIEBOX
++ tristate "piebox keyboard"
++ default n
++ help
++ Say Y here to enable the keyboard on piebox board.
++
+ config KEYBOARD_AAED2000
+ tristate "AAED-2000 keyboard"
+ depends on MACH_AAED2000
+diff -Naur linux-2.6.29/drivers/input/keyboard/Makefile linux-2.6.29-v2010041601/drivers/input/keyboard/Makefile
+--- linux-2.6.29/drivers/input/keyboard/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/input/keyboard/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -28,3 +28,4 @@
+ obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
+ obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
+ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
++obj-$(CONFIG_KEYBOARD_PIEBOX) +=piebox-keyboard.o
+\ Kein Zeilenumbruch am Dateiende.
+diff -Naur linux-2.6.29/drivers/input/keyboard/piebox-keyboard.c linux-2.6.29-v2010041601/drivers/input/keyboard/piebox-keyboard.c
+--- linux-2.6.29/drivers/input/keyboard/piebox-keyboard.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/input/keyboard/piebox-keyboard.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,329 @@
++/*******************************
++*********************************/
++#include <linux/module.h>
++
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/sched.h>
++#include <linux/pm.h>
++#include <linux/sysctl.h>
++#include <linux/proc_fs.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <linux/input.h>
++#include <asm/mpc5121_struct.h>
++
++#include <linux/io.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++
++#define DRV_NAME "piebox-keyboard"
++struct mpc5121_gpio_struct *get_mpc5121_gpio(void);
++
++enum{
++ GPIO_INTERRUPT_ANY_CHANGED=0,
++ GPIO_INTERRUPT_LOW_TO_HIGHT,
++ GPIO_INTERRUPT_HIGHT_TO_LOW,
++ GPIO_INTERRUPT_PULSE2
++
++};
++#define GPIO_INTERRUPT_MASK 3
++static unsigned char gpio_number[]={GPIO_KEY_VOL,GPIO_KEY_MENU,GPIO_KEY_LCD,GPIO_SYSTEM_START_NORFLASH};
++#define PIE_BOX_KEY_NUMBES sizeof(gpio_number)/sizeof(gpio_number[0])
++
++#define PIE_BOX_KEY_MASK (GPIO_BIT_OFFSET(GPIO_KEY_VOL)|GPIO_BIT_OFFSET(GPIO_KEY_MENU)|GPIO_BIT_OFFSET(GPIO_KEY_LCD)|GPIO_BIT_OFFSET(GPIO_SYSTEM_START_NORFLASH))
++
++
++/*
++struct mpc5121_gpio_struct{
++ u32 gpdir;
++ u32 gpodr;
++ u32 gpdat;
++ u32 gpier;
++ u32 gpier;
++ u32 gpimr;
++ u32 gpicr1;
++ u32 gpicr2;
++};
++*/
++struct piebox_keyboard_struct{
++ unsigned char *gpio_number;
++ char name[128];
++ char phys[64];
++ struct input_dev *dev;
++ struct mpc5121_gpio_struct *gpio;
++ u32 irq;
++ u32 keymap[32];
++ u32 keystatus;
++ struct timer_list keydetect_timer;
++
++};
++
++static irqreturn_t piebox_keyboard_int_server(int irq, void *dev_id)
++{
++
++ struct piebox_keyboard_struct *keyboard=dev_id;
++ u32 iostatus,index,flags=0,ievent,ievent_dsable;
++ iostatus=keyboard->gpio->gpdat;
++ ievent=keyboard->gpio->gpier;
++ ievent_dsable=0;
++ /*printk("%s() line:%d keystatus=0x%08x\n",__FUNCTION__,__LINE__,iostatus);*/
++ for(index=0;index<PIE_BOX_KEY_NUMBES;index++)
++ {
++ if(ievent&GPIO_BIT_OFFSET(keyboard->gpio_number[index]))
++ {
++ flags=1;
++ break;
++ }
++ }
++ if(!flags)
++ {
++ return IRQ_NONE;
++ }
++ for(index=0;index<PIE_BOX_KEY_NUMBES;index++)
++ {
++ ievent_dsable|=GPIO_BIT_OFFSET(keyboard->gpio_number[index]);
++ }
++ keyboard->gpio->gpier=ievent_dsable;
++ mod_timer(&keyboard->keydetect_timer, jiffies + HZ/20);
++ return IRQ_HANDLED;
++}
++static int piebox_keybaord_map_init(struct piebox_keyboard_struct *piebox_keyboard)
++{
++ int i;
++ if(PIE_BOX_KEY_NUMBES>4)
++ {
++ printk(KERN_ERR"too many keys unmaped\n");
++ return -1;
++ }
++ piebox_keyboard->keymap[GPIO_KEY_MENU]=KEY_F3;/* home */
++ piebox_keyboard->keymap[GPIO_KEY_LCD]=KEY_F4;/* backlight */
++ piebox_keyboard->keymap[GPIO_KEY_VOL]=KEY_F5;/* vol */
++ piebox_keyboard->keymap[GPIO_SYSTEM_START_NORFLASH]=KEY_F6;/* recovery */
++ for(i=0;i<32;i++)
++ {
++ if(piebox_keyboard->keymap[i])
++ {
++ set_bit(piebox_keyboard->keymap[i], piebox_keyboard->dev->keybit);
++ }
++ }
++ return 0;
++}
++static void piebox_keyboard_int_config_enable(struct piebox_keyboard_struct *piebox_keyboard)
++{
++ struct mpc5121_gpio_struct *gpio=piebox_keyboard->gpio;
++ unsigned char *gpios=piebox_keyboard->gpio_number;
++ int index,number,icr1,icr2,imask;
++
++ icr1=gpio->gpicr1;
++ icr2=gpio->gpicr2;
++ imask=gpio->gpimr;
++
++ for(index=0;index<PIE_BOX_KEY_NUMBES;index++)
++ {
++ number=gpios[index];
++ if(number<16)
++ {
++ icr1&=~(GPIO_INTERRUPT_MASK<<(30-number*2));
++ icr1|=(GPIO_INTERRUPT_HIGHT_TO_LOW<<(30-number*2));
++ }
++ else
++ {
++ icr2&=~(GPIO_INTERRUPT_MASK<<(30-(number-16)*2));
++ icr2|=(GPIO_INTERRUPT_HIGHT_TO_LOW<<(30-(number-16)*2));
++ }
++ imask|=GPIO_BIT_OFFSET(number);
++ }
++ gpio->gpicr1=icr1;
++ gpio->gpicr2=icr2;
++ gpio->gpimr=imask;
++
++
++
++}
++static void key_detect_timer(unsigned long data)
++{
++ struct piebox_keyboard_struct *keyboard= (struct esdhc_host *)data;
++ u32 iostatus,index;
++ iostatus=keyboard->gpio->gpdat;
++ iostatus&=PIE_BOX_KEY_MASK;
++ /*printk("iostatus:%08x\n",iostatus);*/
++ if(iostatus!=keyboard->keystatus)
++ {
++ for(index=0;index<PIE_BOX_KEY_NUMBES;index++)
++ {
++
++ if(iostatus&GPIO_BIT_OFFSET(keyboard->gpio_number[index]))
++ {
++ input_report_key(keyboard->dev, keyboard->keymap[keyboard->gpio_number[index]], 0x00);
++ }
++ else
++ {
++ input_report_key(keyboard->dev, keyboard->keymap[keyboard->gpio_number[index]], 0x01);
++
++ }
++
++ }
++ input_sync(keyboard->dev);
++ keyboard->keystatus=iostatus;
++ }
++ if((PIE_BOX_KEY_MASK&iostatus)!=PIE_BOX_KEY_MASK)
++ mod_timer(&keyboard->keydetect_timer, jiffies + HZ/10);
++
++}
++static int piebox_keyboard_probe(struct of_device *op, const struct of_device_id *match)
++{
++ /*struct platform_device *pdev = to_platform_device(dev);*/
++
++
++ int err=-1;
++
++ struct piebox_keyboard_struct *piebox_keyboard;
++ struct input_dev *inputdev;
++
++ piebox_keyboard=kzalloc(sizeof(struct piebox_keyboard_struct), GFP_KERNEL);
++ if(!piebox_keyboard)
++ {
++ printk(KERN_ERR"alloc memory failed.\n");
++ return -ENOMEM;
++ }
++
++ piebox_keyboard->irq=irq_of_parse_and_map(op->node, 0);
++ if(NO_IRQ==piebox_keyboard->irq)
++ {
++ printk(KERN_ERR"no irq.\n");
++ return -ENOMEM;
++ }
++ printk("piebox-keyboard irq:%d\n",piebox_keyboard->irq);
++
++ piebox_keyboard->gpio=get_mpc5121_gpio();/*ioremap(GENERAL_GPIO_BASE+MPC5121_CFG_IMMR,sizeof(struct mpc5121_gpio_struct));*/
++ if(!piebox_keyboard->gpio)
++ {
++ printk(KERN_ERR"Unmaped gpio memory.\n");
++ return -1;
++ }
++
++ strcpy(piebox_keyboard->name,"piebox-keyboard");
++ strcpy(piebox_keyboard->phys,"keyboard/input0");
++
++
++
++ piebox_keyboard->dev=input_allocate_device();
++
++ if(!piebox_keyboard->dev)
++ {
++ printk(KERN_ERR"alloc memory failed.\n");
++ err= -ENOMEM;
++ goto failed1;
++ }
++ piebox_keyboard->gpio_number=gpio_number;
++
++ inputdev=piebox_keyboard->dev;
++ inputdev->name=piebox_keyboard->name;
++ inputdev->phys=piebox_keyboard->phys;
++ inputdev->dev.parent = &op->dev;
++ inputdev->evbit[0] =BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
++ set_bit(EV_MSC, inputdev->evbit);
++ set_bit(MSC_SCAN, inputdev->mscbit);
++ inputdev->id.bustype=BUS_HOST;
++ inputdev->id.vendor=0x001;
++ inputdev->id.product=0x002;
++ inputdev->id.version=0x0100;
++ input_set_drvdata(inputdev, piebox_keyboard);
++ if(piebox_keybaord_map_init(piebox_keyboard))
++ {
++ err= -1;
++ printk(KERN_ERR"keymap failed.\n");
++ goto failed2;
++ }
++
++ err = input_register_device(inputdev);
++ if (err)
++ {
++ printk(KERN_ERR"input register failed.\n");
++ goto failed2;
++ }
++
++
++ err = request_irq(piebox_keyboard->irq, piebox_keyboard_int_server,
++ IRQF_SHARED|IRQF_DISABLED,
++ "piebox-keybaord", piebox_keyboard);
++ if(err)
++ {
++ printk(KERN_ERR"Request irq:%d failed.\n",piebox_keyboard->irq);
++ goto failed3;
++ }
++ init_timer(&piebox_keyboard->keydetect_timer);
++ piebox_keyboard->keydetect_timer.data = (unsigned long)piebox_keyboard;
++ piebox_keyboard->keydetect_timer.function =key_detect_timer;
++ piebox_keyboard->keydetect_timer.expires = jiffies + HZ/20;
++ add_timer(&piebox_keyboard->keydetect_timer);
++ dev_set_drvdata(&op->dev, (void *)piebox_keyboard);
++ piebox_keyboard_int_config_enable(piebox_keyboard);
++ return 0;
++failed3:
++failed2:
++ input_free_device(piebox_keyboard->dev);
++ failed1:
++ iounmap(piebox_keyboard->gpio);
++ kfree(piebox_keyboard);
++ return err;
++}
++
++static int piebox_keyboard_remove(struct of_device *op)
++{
++
++ struct piebox_keyboard_struct *piebox_keyboard = dev_get_drvdata(&op->dev);
++
++ free_irq(piebox_keyboard->irq,piebox_keyboard);
++ del_timer(&piebox_keyboard->keydetect_timer);
++ input_free_device(piebox_keyboard->dev);
++ /*iounmap(piebox_keyboard->gpio);*/
++ kfree(piebox_keyboard);
++ return 0;
++}
++
++
++static struct of_device_id mpc512x_keybaord_of_match[] = {
++ { .compatible = "piebox-keyboard", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, mpc512x_keybaord_of_match);
++
++static struct of_platform_driver piebox_keyboard_of_platform_driver = {
++ .owner = THIS_MODULE,
++ .name =DRV_NAME ,
++ .match_table = mpc512x_keybaord_of_match,
++ .probe = piebox_keyboard_probe,
++ .remove = piebox_keyboard_remove,
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init piebox_keyboard_init(void)
++{
++ return of_register_platform_driver(&piebox_keyboard_of_platform_driver);
++}
++
++static void __exit piebox_keybaord_exit(void)
++{
++ of_unregister_platform_driver(&piebox_keyboard_of_platform_driver);
++}
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("piebox keyboard driver");
++
++module_init(piebox_keyboard_init);
++module_exit(piebox_keybaord_exit);
++
++
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Cloudy chen<chen_yunsong@mtcera.com>");
++MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
++MODULE_ALIAS("platform:gpio-keys");
++
+diff -Naur linux-2.6.29/drivers/input/touchscreen/chacha_mt4.c linux-2.6.29-v2010041601/drivers/input/touchscreen/chacha_mt4.c
+--- linux-2.6.29/drivers/input/touchscreen/chacha_mt4.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/input/touchscreen/chacha_mt4.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,348 @@
++/*
++ * drivers/input/touchscreen/chacha_mt4.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/module.h>
++#include <linux/hrtimer.h>
++#include <linux/slab.h>
++#include <linux/input.h>
++#include <linux/interrupt.h>
++#include <linux/i2c.h>
++#include <linux/i2c/chacha_mt4.h>
++#include <linux/delay.h>
++
++#define REG_LENGTH 11
++
++__u8 mt4_data[REG_LENGTH];
++
++// buffer map
++#define REG_TOUCH_STATUS 0x0
++#define REG_X1_LOW 0x1
++#define REG_X1_HIGH 0x2
++#define REG_Y1_LOW 0x3
++#define REG_Y1_HIGH 0x4
++#define REG_X2_LOW 0x5
++#define REG_X2_HIGH 0x6
++#define REG_Y2_LOW 0x7
++#define REG_Y2_HIGH 0x8
++#define REG_STRENGTH_LOW 0x9
++#define REG_STRENGTH_HIGH 0xa
++#define REG_RESERVE_1 0xb
++#define REG_FIRMWARE_ID 0xc
++#define REG_X_SENSITIVITY 0xd
++#define REG_Y_SENSITIVITY 0xe
++#define REG_RESERVE_2 0xf
++#define REG_RESERVE_3 0x10
++#define REG_RESERVE_4 0x11
++#define REG_RESERVE_5 0x12
++#define REG_OFFSET 0x13
++#define REG_POWER_MODE 0x14
++#define REG_EEPROM_WRITE 0x15
++
++enum chacha_mt4_mode {
++ watch_mode = 0,
++ watch_mode_e = 0x0e,
++ active_mode = 0x10,
++ fast_scan_mode = 0x20,
++ freeze_mode = 0x90
++};
++
++struct mt4 {
++ struct input_dev *input;
++ char phys[32];
++ struct i2c_client *client;
++
++ spinlock_t lock;
++
++ u16 model;
++
++ unsigned pendown;
++ int irq;
++
++ int (*get_pendown_state)(void);
++ void (*clear_penirq)(void);
++ int (*if_penirq)(void);
++ void (*enable_irq)(int);
++
++ struct delayed_work work;
++};
++
++#define EVENT_PENDOWN 1
++#define EVENT_REPEAT 2
++#define EVENT_PENUP 3
++
++static void chacha_mt4_ts_poscheck(struct work_struct *work)
++{
++ int event, fingers, x1, y1, x2, y2;
++ struct mt4 *ts = container_of(work, struct mt4, work.work);
++ struct i2c_adapter *adapter = to_i2c_adapter(ts->client->dev.parent);
++
++ struct i2c_msg msg = {
++ .addr = ts->client->addr,
++ .flags = I2C_M_RD,
++ .buf = mt4_data,
++ .len = sizeof(mt4_data)
++ };
++
++ memset(&mt4_data, 0, sizeof(mt4_data));
++
++ if (i2c_transfer(adapter, &msg, 1) != 1) {
++ dev_err(&ts->client->dev, "Unable to transfer i2c request.\n");
++ goto out;
++ }
++
++ fingers = mt4_data[REG_TOUCH_STATUS] & 0x03;
++ if (fingers == 3)
++ fingers--;
++
++ x1 = mt4_data[REG_X1_LOW] | mt4_data[REG_X1_HIGH] << 8;
++ y1 = mt4_data[REG_Y1_LOW] | mt4_data[REG_Y1_HIGH] << 8;
++ x2 = mt4_data[REG_X2_LOW] | mt4_data[REG_X2_HIGH] << 8;
++ y2 = mt4_data[REG_Y2_LOW] | mt4_data[REG_Y2_HIGH] << 8;
++
++ event = (fingers == 0) ? EVENT_PENUP : EVENT_PENDOWN;
++
++#if 0
++ printk("mode: %02d, ", (mt4_data[REG_TOUCH_STATUS] & 0x30) >> 4);
++
++ if (fingers == 0)
++ printk("%s ", "PENUP");
++ if (fingers > 0)
++ printk("%04d,%04d ", x1, y1);
++ if (fingers >= 2)
++ printk("%04d,%04d ", x2, y2);
++ printk("\n");
++#endif
++
++ if (event == EVENT_PENDOWN) {
++// input_report_key(ts->input, BTN_TOOL_FINGER, fingers == 1);
++// input_report_key(ts->input, BTN_TOOL_DOUBLETAP, fingers == 2);
++// input_report_key(ts->input, BTN_TOOL_TRIPLETAP, fingers > 2);
++
++ input_report_key(ts->input, BTN_TOUCH, fingers > 0);
++ input_report_abs(ts->input, ABS_X, x1);
++ input_report_abs(ts->input, ABS_Y, y1);
++ input_report_abs(ts->input, ABS_PRESSURE, 1);
++
++ if (fingers == 2) {
++ input_report_abs(ts->input, ABS_X, x2);
++ input_report_abs(ts->input, ABS_Y, y2);
++ }
++
++ input_sync(ts->input);
++
++ } else if (event == EVENT_PENUP) {
++ input_report_key(ts->input, BTN_TOUCH, 0);
++ input_report_abs(ts->input, ABS_PRESSURE, 0);
++ input_sync(ts->input);
++ }
++ out:
++ ts->enable_irq(1);
++}
++
++static irqreturn_t chacha_mt4_irq(int irq, void *handle)
++{
++ struct mt4 *ts = handle;
++
++ if (ts->if_penirq && !ts->if_penirq())
++ return IRQ_NONE;
++
++ /* the touch screen controller chip is hooked up to the cpu
++ * using i2c and a single interrupt line. the interrupt line
++ * is pulled low whenever someone taps the screen. to deassert
++ * the interrupt line we need to acknowledge the interrupt by
++ * communicating with the controller over the slow i2c bus.
++ *
++ * we can't acknowledge from interrupt context since the i2c
++ * bus controller may sleep, so we just disable the interrupt
++ * here and handle the acknowledge using delayed work.
++ */
++
++ if (ts->enable_irq)
++ ts->enable_irq(0);
++ if (ts->clear_penirq)
++ ts->clear_penirq();
++
++ schedule_delayed_work(&ts->work, 0);
++
++ return IRQ_HANDLED;
++}
++
++static int chacha_mt4_calibration(struct mt4 *ts)
++{
++ struct i2c_adapter *adapter = to_i2c_adapter(ts->client->dev.parent);
++
++ u8 cmd[]= {0x14, 0x40, 0xf3};
++
++ struct i2c_msg msg = {
++ .addr = ts->client->addr,
++ .flags = 0,
++ .buf = cmd,
++ .len = sizeof(cmd)
++ };
++
++ if (i2c_transfer(adapter, &msg, 1) != 1) {
++ dev_err(&ts->client->dev, "Unable to transfer i2c request.\n");
++ return -EIO;
++ }
++
++ return 0;
++}
++
++#define MODE_SELECT_BYTE 0x14
++
++static inline int chacha_mt4_mode_select(struct mt4 *tsc, enum chacha_mt4_mode mode)
++{
++ return i2c_smbus_write_byte_data(tsc->client, MODE_SELECT_BYTE, (u8)mode);
++}
++
++static int chacha_mt4_ts_open(struct input_dev *dev)
++{
++ return 0;
++}
++
++static void chacha_mt4_ts_close(struct input_dev *dev)
++{
++}
++
++extern struct chacha_mt4_platform_data ts_chacha_mt4_data;
++
++static int chacha_mt4_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct input_dev *input_dev;
++ struct mt4 *ts;
++ int err;
++
++ if (!i2c_check_functionality(client->adapter,
++ I2C_FUNC_SMBUS_READ_WORD_DATA))
++ return -EIO;
++
++ client->dev.platform_data = &ts_chacha_mt4_data;
++
++ ts = kzalloc(sizeof(struct mt4), GFP_KERNEL);
++ input_dev = input_allocate_device();
++ if (!ts || !input_dev) {
++ err = -ENOMEM;
++ goto err_free_mem;
++ }
++
++ i2c_set_clientdata(client, ts);
++
++ ts->client = client;
++ ts->input = input_dev;
++ ts->get_pendown_state = ts_chacha_mt4_data.get_pendown_state;
++ ts->clear_penirq = ts_chacha_mt4_data.clear_penirq;
++ ts->if_penirq = ts_chacha_mt4_data.if_penirq;
++ ts->enable_irq = ts_chacha_mt4_data.enable_irq;
++ ts->irq = client->irq;
++ INIT_DELAYED_WORK(&ts->work, chacha_mt4_ts_poscheck);
++
++ snprintf(ts->phys, sizeof(ts->phys), "%s/input0",
++ dev_name(&client->dev));
++
++ input_dev->name = "TOPSTD ChaCha M-T4 Touchscreen";
++ input_dev->phys = ts->phys;
++ input_dev->id.bustype = BUS_I2C;
++ input_dev->open = chacha_mt4_ts_open;
++ input_dev->close = chacha_mt4_ts_close;
++
++ input_dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
++ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
++
++ set_bit(EV_ABS, input_dev->evbit);
++ set_bit(ABS_X, input_dev->absbit);
++ set_bit(ABS_Y, input_dev->absbit);
++ set_bit(ABS_PRESSURE, input_dev->absbit);
++
++ input_set_abs_params(input_dev, ABS_X, 0, 10240, 0, 0);
++ input_set_abs_params(input_dev, ABS_Y, 0, 5632, 0, 0);
++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0, 0);
++
++#if 1
++ ts_chacha_mt4_data.gpio_attb(0);
++ udelay(30);
++ chacha_mt4_calibration(ts);
++ msleep_interruptible(500);
++ udelay(50);
++ chacha_mt4_mode_select(ts, fast_scan_mode);
++ ts_chacha_mt4_data.gpio_attb(1);
++#endif
++
++ ts_chacha_mt4_data.init_platform_hw();
++
++ err = request_irq(ts->irq, chacha_mt4_irq, IRQF_SHARED,
++ client->dev.driver->name, ts);
++ if (err < 0) {
++ dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
++ goto err_free_mem;
++ }
++
++ err = input_register_device(input_dev);
++ if (err)
++ goto err_free_irq;
++
++ dev_info(&client->dev, "registered with irq (%d)\n", ts->irq);
++ return 0;
++
++ err_free_irq:
++ free_irq(ts->irq, ts);
++ err_free_mem:
++ input_free_device(input_dev);
++ kfree(ts);
++
++ return err;
++}
++
++static int chacha_mt4_remove(struct i2c_client *client)
++{
++ struct mt4 *ts = i2c_get_clientdata(client);
++ struct chacha_mt4_platform_data *pdata;
++
++ pdata = client->dev.platform_data;
++ pdata->exit_platform_hw();
++
++ free_irq(ts->irq, ts);
++ input_unregister_device(ts->input);
++ kfree(ts);
++
++ return 0;
++}
++
++static struct i2c_device_id chacha_mt4_idtable[] = {
++ { "chacha_mt4", 0 },
++ { }
++};
++
++MODULE_DEVICE_TABLE(i2c, chacha_mt4_idtable);
++
++static struct i2c_driver mt4_driver = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "chacha_mt4"
++ },
++ .id_table = chacha_mt4_idtable,
++ .probe = chacha_mt4_probe,
++ .remove = chacha_mt4_remove,
++};
++
++static int __init chacha_mt4_init(void)
++{
++ return i2c_add_driver(&mt4_driver);
++}
++
++static void __exit chacha_mt4_exit(void)
++{
++ i2c_del_driver(&mt4_driver);
++}
++
++module_init(chacha_mt4_init);
++module_exit(chacha_mt4_exit);
++
++MODULE_AUTHOR("Wang Yang <wang_yang@mtcera.com>");
++MODULE_DESCRIPTION("ChaCha M-T4 TouchScreen Driver");
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.29/drivers/input/touchscreen/Kconfig linux-2.6.29-v2010041601/drivers/input/touchscreen/Kconfig
+--- linux-2.6.29/drivers/input/touchscreen/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/input/touchscreen/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -408,4 +408,25 @@
+ To compile this driver as a module, choose M here: the
+ module will be called tsc2007.
+
++config TOUCHSCREEN_CHACHA_MT4
++ tristate "ChaCha M-T4 based touchscreens"
++ depends on I2C
++ help
++ Say Y here if you have a ChaCha M-T4 based touchscreen.
++
++ If unsure, say N.
++
++ To compile this driver as a module, choose M here: the
++ module will be called ChaCha-M-T4.
++
++config TOUCHSCREEN_MA17P0X
++ tristate "MA17P0X touchscreens"
++ depends on I2C
++ help
++ Say Y here if you have a MA17P0X touchscreen.
++
++ If unsure, say N.
++
++ To compile this driver as a module, choose M here: the
++ module will be called MA17P0X.
+ endif
+diff -Naur linux-2.6.29/drivers/input/touchscreen/ma17p0x.c linux-2.6.29-v2010041601/drivers/input/touchscreen/ma17p0x.c
+--- linux-2.6.29/drivers/input/touchscreen/ma17p0x.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/input/touchscreen/ma17p0x.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,332 @@
++/*
++ * drivers/input/touchscreen/ma17p0x.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/module.h>
++#include <linux/hrtimer.h>
++#include <linux/slab.h>
++#include <linux/input.h>
++#include <linux/interrupt.h>
++#include <linux/i2c.h>
++#include <linux/i2c/ma17p0x.h>
++#include <linux/delay.h>
++
++__u8 ma17p0x[19];
++
++// buffer map
++#define REG_TOTAL_DATA_LEN 0x0
++#define REG_RESERVED_0 0x1
++#define REG_NUM_OF_FINGER 0x2
++#define REG_X1_HIGH_BYTE 0x3
++#define REG_X1_LOW_BYTE 0x4
++#define REG_Y1_HIGH_BYTE 0x5
++#define REG_Y1_LOW_BYTE 0x6
++#define REG_X2_HIGH_BYTE 0x7
++#define REG_X2_LOW_BYTE 0x8
++#define REG_Y2_HIGH_BYTE 0x9
++#define REG_Y2_LOW_BYTE 0xa
++#define REG_X3_HIGH_BYTE 0xb
++#define REG_X3_LOW_BYTE 0xc
++#define REG_Y3_HIGH_BYTE 0xd
++#define REG_Y3_LOW_BYTE 0xe
++#define REG_X4_HIGH_BYTE 0xf
++#define REG_X4_LOW_BYTE 0x10
++#define REG_Y4_HIGH_BYTE 0x11
++#define REG_Y4_LOW_BYTE 0x12
++
++enum ma17p0x_mode {
++ watch_mode = 0,
++ watch_mode_e = 0x0e,
++ active_mode = 0x10,
++ fast_scan_mode = 0x20,
++ freeze_mode = 0x90
++};
++
++struct mt4 {
++ struct input_dev *input;
++ char phys[32];
++ struct i2c_client *client;
++
++ spinlock_t lock;
++
++ u16 model;
++
++ unsigned pendown;
++ int irq;
++
++ int (*get_pendown_state)(void);
++ void (*clear_penirq)(void);
++ int (*if_penirq)(void);
++ void (*enable_irq)(int);
++
++ struct delayed_work work;
++};
++
++struct ts_point {
++ int x;
++ int y;
++};
++
++#define EVENT_PENDOWN 1
++#define EVENT_REPEAT 2
++#define EVENT_PENUP 3
++
++#define get_val(_high, _low) (_high << 4 | _low >> 4)
++
++static void ma17p0x_ts_poscheck(struct work_struct *work)
++{
++ struct mt4 *ts = container_of(work, struct mt4, work.work);
++ struct i2c_adapter *adapter = to_i2c_adapter(ts->client->dev.parent);
++ struct ts_point pt[4];
++ int i, fingers = 0;
++ u8 data_length;
++ int event = EVENT_PENUP;
++
++ struct i2c_msg msg[] = {
++ {
++ .addr = ts->client->addr,
++ .flags = I2C_M_RD,
++ .buf = &data_length,
++ .len = 1
++ },
++ {
++ .addr = ts->client->addr,
++ .flags = I2C_M_RD,
++ .buf = ma17p0x,
++ .len = sizeof(ma17p0x)
++ }
++ };
++
++ if ((i2c_transfer(adapter, &msg[0], 1) != 1)) {
++ if (ts->get_pendown_state() == 0)
++ goto pen_up;
++ goto out;
++ }
++
++ msg[1].len = data_length + 1;
++ if (i2c_transfer(adapter, &msg[1], 1) != 1) {
++ if (ts->get_pendown_state() == 0)
++ goto pen_up;
++ goto out;
++ }
++
++ fingers = ma17p0x[REG_NUM_OF_FINGER];
++ if (fingers <= 0 || fingers > 4)
++ goto out;
++
++ event = EVENT_PENDOWN;
++ for (i = 0; i < fingers; i++) {
++ pt[i].x = get_val(ma17p0x[REG_X1_HIGH_BYTE + 4 * i],
++ ma17p0x[REG_X1_LOW_BYTE + 4 * i]);
++ pt[i].y = get_val(ma17p0x[REG_Y1_HIGH_BYTE + 4 * i],
++ ma17p0x[REG_Y1_LOW_BYTE + 4 * i]);
++ }
++
++pen_up:
++
++#if 0
++ if (event == EVENT_PENUP)
++ printk("%s\n", "PENUP");
++ if (event == EVENT_PENDOWN) {
++ for (i = 0; i < fingers; i++)
++ printk("%04d,%04d ", pt[i].x, pt[i].y);
++ printk("\n");
++ }
++#endif
++
++ if (event == EVENT_PENDOWN) {
++
++ input_report_key(ts->input, BTN_TOUCH, 1);
++
++ for (i = 0; i < fingers; i++) {
++ input_report_abs(ts->input, ABS_X, pt[i].x);
++ input_report_abs(ts->input, ABS_Y, pt[i].y);
++ }
++
++ input_report_abs(ts->input, ABS_PRESSURE, 1);
++ input_sync(ts->input);
++
++ } else if (event == EVENT_PENUP) {
++ input_report_key(ts->input, BTN_TOUCH, 0);
++ input_report_abs(ts->input, ABS_PRESSURE, 0);
++ input_sync(ts->input);
++ }
++out:
++ ts->enable_irq(1);
++}
++
++static irqreturn_t ma17p0x_irq(int irq, void *handle)
++{
++ struct mt4 *ts = handle;
++
++ if (ts->if_penirq && !ts->if_penirq())
++ return IRQ_NONE;
++
++ /* the touch screen controller chip is hooked up to the cpu
++ * using i2c and a single interrupt line. the interrupt line
++ * is pulled low whenever someone taps the screen. to deassert
++ * the interrupt line we need to acknowledge the interrupt by
++ * communicating with the controller over the slow i2c bus.
++ *
++ * we can't acknowledge from interrupt context since the i2c
++ * bus controller may sleep, so we just disable the interrupt
++ * here and handle the acknowledge using delayed work.
++ */
++
++ if (ts->enable_irq)
++ ts->enable_irq(0);
++ if (ts->clear_penirq)
++ ts->clear_penirq();
++
++ schedule_delayed_work(&ts->work, 0);
++
++ return IRQ_HANDLED;
++}
++
++#define MODE_SELECT_BYTE 0x14
++
++static inline int ma17p0x_mode_select(struct mt4 *tsc, enum ma17p0x_mode mode)
++{
++ return i2c_smbus_write_byte_data(tsc->client, MODE_SELECT_BYTE, (u8)mode);
++}
++
++static int ma17p0x_ts_open(struct input_dev *dev)
++{
++ return 0;
++}
++
++static void ma17p0x_ts_close(struct input_dev *dev)
++{
++}
++
++extern struct ma17p0x_platform_data ts_ma17p0x_data;
++
++static int ma17p0x_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct input_dev *input_dev;
++ struct mt4 *ts;
++ int err;
++
++ if (!i2c_check_functionality(client->adapter,
++ I2C_FUNC_SMBUS_READ_WORD_DATA))
++ return -EIO;
++
++ client->dev.platform_data = &ts_ma17p0x_data;
++
++ ts = kzalloc(sizeof(struct mt4), GFP_KERNEL);
++ input_dev = input_allocate_device();
++ if (!ts || !input_dev) {
++ err = -ENOMEM;
++ goto err_free_mem;
++ }
++
++ i2c_set_clientdata(client, ts);
++
++ ts->client = client;
++ ts->input = input_dev;
++ ts->get_pendown_state = ts_ma17p0x_data.get_pendown_state;
++ ts->clear_penirq = ts_ma17p0x_data.clear_penirq;
++ ts->if_penirq = ts_ma17p0x_data.if_penirq;
++ ts->enable_irq = ts_ma17p0x_data.enable_irq;
++ ts->irq = client->irq;
++ INIT_DELAYED_WORK(&ts->work, ma17p0x_ts_poscheck);
++
++ snprintf(ts->phys, sizeof(ts->phys), "%s/input0",
++ dev_name(&client->dev));
++
++ input_dev->name = "MA17P0X Touchscreen";
++ input_dev->phys = ts->phys;
++ input_dev->id.bustype = BUS_I2C;
++ input_dev->open = ma17p0x_ts_open;
++ input_dev->close = ma17p0x_ts_close;
++
++ input_dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
++ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
++
++ set_bit(EV_ABS, input_dev->evbit);
++ set_bit(ABS_X, input_dev->absbit);
++ set_bit(ABS_Y, input_dev->absbit);
++ set_bit(ABS_PRESSURE, input_dev->absbit);
++
++ input_set_abs_params(input_dev, ABS_X, 0, 4096, 0, 0);
++ input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0);
++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0, 0);
++
++ ts_ma17p0x_data.init_platform_hw();
++
++ err = request_irq(ts->irq, ma17p0x_irq, IRQF_SHARED,
++ client->dev.driver->name, ts);
++ if (err < 0) {
++ dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
++ goto err_free_mem;
++ }
++
++ err = input_register_device(input_dev);
++ if (err)
++ goto err_free_irq;
++
++ dev_info(&client->dev, "registered with irq (%d)\n", ts->irq);
++ return 0;
++
++ err_free_irq:
++ free_irq(ts->irq, ts);
++ err_free_mem:
++ input_free_device(input_dev);
++ kfree(ts);
++
++ return err;
++}
++
++static int ma17p0x_remove(struct i2c_client *client)
++{
++ struct mt4 *ts = i2c_get_clientdata(client);
++ struct ma17p0x_platform_data *pdata;
++
++ pdata = client->dev.platform_data;
++ pdata->exit_platform_hw();
++
++ free_irq(ts->irq, ts);
++ input_unregister_device(ts->input);
++ kfree(ts);
++
++ return 0;
++}
++
++static struct i2c_device_id ma17p0x_idtable[] = {
++ { "ma17p0x", 0 },
++ { }
++};
++
++MODULE_DEVICE_TABLE(i2c, ma17p0x_idtable);
++
++static struct i2c_driver ma17p0x_driver = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "ma17p0x"
++ },
++ .id_table = ma17p0x_idtable,
++ .probe = ma17p0x_probe,
++ .remove = ma17p0x_remove,
++};
++
++static int __init ma17p0x_init(void)
++{
++ return i2c_add_driver(&ma17p0x_driver);
++}
++
++static void __exit ma17p0x_exit(void)
++{
++ i2c_del_driver(&ma17p0x_driver);
++}
++
++module_init(ma17p0x_init);
++module_exit(ma17p0x_exit);
++
++MODULE_AUTHOR("Wang Yang <wang_yang@mtcera.com>");
++MODULE_DESCRIPTION("MA17P0X TouchScreen Driver");
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.29/drivers/input/touchscreen/Makefile linux-2.6.29-v2010041601/drivers/input/touchscreen/Makefile
+--- linux-2.6.29/drivers/input/touchscreen/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/input/touchscreen/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -26,6 +26,8 @@
+ obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
+ obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
+ obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
++obj-$(CONFIG_TOUCHSCREEN_CHACHA_MT4) += chacha_mt4.o
++obj-$(CONFIG_TOUCHSCREEN_MA17P0X) += ma17p0x.o
+ obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o
+ obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
+diff -Naur linux-2.6.29/drivers/input/touchscreen/wm97xx-core.c linux-2.6.29-v2010041601/drivers/input/touchscreen/wm97xx-core.c
+--- linux-2.6.29/drivers/input/touchscreen/wm97xx-core.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/input/touchscreen/wm97xx-core.c 2010-04-13 20:23:26.000000000 +0200
+@@ -69,7 +69,7 @@
+ * Documentation/input/input-programming.txt for more details.
+ */
+
+-static int abs_x[3] = {350, 3900, 5};
++static int abs_x[3] = {350, 3900, 15};
+ module_param_array(abs_x, int, NULL, 0);
+ MODULE_PARM_DESC(abs_x, "Touchscreen absolute X min, max, fuzz");
+
+diff -Naur linux-2.6.29/drivers/mmc/host/Kconfig linux-2.6.29-v2010041601/drivers/mmc/host/Kconfig
+--- linux-2.6.29/drivers/mmc/host/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/mmc/host/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -65,6 +65,31 @@
+
+ If unsure, say Y.
+
++config MMC_MPC5121
++ tristate "Freescale MPC5121 Secure Digital Host Controller Interface support"
++ depends on PPC_MPC512x
++ default n
++ help
++ This selects the SD Host Controller Interface on the MPC5121.
++ If you have a MPC5121 Platform with SD slot, say Y or M here.
++
++config MMC_MPC5121_USE_DMA
++ bool "Use DMA in MPC5121 SDHC driver" if MMC_MPC5121
++ default y
++ help
++ This enables DMA in the MPC5121 SD Host Controller driver.
++
++ If unsure, say Y.
++
++config MMC_MPC5121_USE_CARD_INSERTION_INT
++ bool "Use card insertion interrupt in MPC5121 SDHC driver" if MMC_MPC5121
++ default n
++ help
++ This enables use of card insertion interrupt in the MPC5121 SD Host Controller driver.
++ This option will not work on ADS5121.
++
++ If unsure, say N.
++
+ config MMC_OMAP
+ tristate "TI OMAP Multimedia Card Interface support"
+ depends on ARCH_OMAP
+diff -Naur linux-2.6.29/drivers/mmc/host/Makefile linux-2.6.29-v2010041601/drivers/mmc/host/Makefile
+--- linux-2.6.29/drivers/mmc/host/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/mmc/host/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -27,4 +27,4 @@
+ obj-$(CONFIG_MMC_S3C) += s3cmci.o
+ obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
+ obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
+-
++obj-$(CONFIG_MMC_MPC5121) += mpc5121_sdhc.o
+diff -Naur linux-2.6.29/drivers/mmc/host/mpc5121_sdhc.c linux-2.6.29-v2010041601/drivers/mmc/host/mpc5121_sdhc.c
+--- linux-2.6.29/drivers/mmc/host/mpc5121_sdhc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/mmc/host/mpc5121_sdhc.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,1301 @@
++/*
++ * drivers/mmc/host/mpc5121_sdhc.c
++ *
++ * Copyright (C) 2008 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Author: <allgosystems.com>
++ *
++ * derived from sdhci.c by Pierre Ossman
++ *
++ * Description:
++ * Freescale MPC5121 Secure Digital Host Controller driver.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/highmem.h>
++#include <linux/dma-mapping.h>
++#include <linux/scatterlist.h>
++#include <linux/uaccess.h>
++#include <linux/irq.h>
++#include <linux/hardirq.h>
++#include <linux/io.h>
++#include <linux/clk.h>
++#include <linux/mmc/mmc.h>
++#include <linux/mmc/host.h>
++#include <linux/mmc/card.h>
++#include <linux/mmc/sd.h>
++#include <linux/mmc/host.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <linux/ioport.h>
++#include <linux/time.h>
++
++#include <asm/of_platform.h>
++#include <asm/dma.h>
++#include <asm/page.h>
++#include <asm/reg.h>
++#include <sysdev/fsl_soc.h>
++
++#include "mpc5121_sdhc.h"
++#include <asm/fsldma.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++
++#include <asm-powerpc/fsldma.h>
++
++#define DATA_SKEW_RATE_STD_4 0x00000003
++
++#define DRIVER_NAME "sdhc"
++
++#define MPC512X_DMA_SDHC 30
++#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
++
++#ifdef DEBUG
++#define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt "\n", \
++ __FUNCTION__, ## args)
++#else
++#define DBG(fmt, args...) do {} while (0)
++#endif
++
++#define J1_SDHC_CLK 0X00000080
++#define K5_SDHC_CMD 0X00000080
++#define J2_SDHC_D0 0X00000080
++#define J3_SDHC_D1_IRQ 0X00000080
++#define J4_SDHC_D2 0X00000080
++#define H2_SDHC_D3_CD 0X00000080
++#define CLK_LINE 0X0C4
++#define CMD_LINE 0X0C8
++#define D0_LINE 0X0CC
++#define D1_LINE 0X0D0
++#define D2_LINE 0X0D4
++#define D3_CD_LINE 0X0D8
++
++
++#define PU_ENABLE 0x00000018
++#define PD_ENABLE 0x00000008
++#define DATA_SKEW_RATE_STD_4 0x00000003
++#define PU_ENABLE_PULL_DOWN 0x00000008
++
++static u32 *write_buf;
++static dma_addr_t sphyaddr;
++static void dma_correction(unsigned long *, unsigned long *, int len);
++
++#ifdef CONFIG_MMC_DEBUG
++static void dump_cmd(struct mmc_command *cmd)
++{
++ printk(KERN_INFO "%s: CMD: opcode: %d ", DRIVER_NAME, cmd->opcode);
++ printk(KERN_INFO "arg: 0x%08x ", cmd->arg);
++ printk(KERN_INFO "flags: 0x%08x\n", cmd->flags);
++}
++
++static void dump_status(const char *func, int sts)
++{
++ unsigned int bitset;
++ printk(KERN_INFO "%s:status: ", func);
++ while (sts) {
++ /* Find the next bit set */
++ bitset = sts & ~(sts - 1);
++ switch (bitset) {
++ case STATUS_CARD_INSERTION:
++ printk(KERN_INFO "CARD_INSERTION|");
++ break;
++ case STATUS_CARD_REMOVAL:
++ printk(KERN_INFO "CARD_REMOVAL |");
++ break;
++ case STATUS_YBUF_EMPTY:
++ printk(KERN_INFO "YBUF_EMPTY |");
++ break;
++ case STATUS_XBUF_EMPTY:
++ printk(KERN_INFO "XBUF_EMPTY |");
++ break;
++ case STATUS_YBUF_FULL:
++ printk(KERN_INFO "YBUF_FULL |");
++ break;
++ case STATUS_XBUF_FULL:
++ printk(KERN_INFO "XBUF_FULL |");
++ break;
++ case STATUS_BUF_UND_RUN:
++ printk(KERN_INFO "BUF_UND_RUN |");
++ break;
++ case STATUS_BUF_OVFL:
++ printk(KERN_INFO "BUF_OVFL |");
++ break;
++ case STATUS_READ_OP_DONE:
++ printk(KERN_INFO "READ_OP_DONE |");
++ break;
++ case STATUS_WR_CRC_ERROR_CODE_MASK:
++ printk(KERN_INFO "WR_CRC_ERROR_CODE |");
++ break;
++ case STATUS_READ_CRC_ERR:
++ printk(KERN_INFO "READ_CRC_ERR |");
++ break;
++ case STATUS_WRITE_CRC_ERR:
++ printk(KERN_INFO "WRITE_CRC_ERR |");
++ break;
++ case STATUS_SDIO_INT_ACTIVE:
++ printk(KERN_INFO "SDIO_INT_ACTIVE |");
++ break;
++ case STATUS_END_CMD_RESP:
++ printk(KERN_INFO "END_CMD_RESP |");
++ break;
++ case STATUS_WRITE_OP_DONE:
++ printk(KERN_INFO "WRITE_OP_DONE |");
++ break;
++ case STATUS_CARD_BUS_CLK_RUN:
++ printk(KERN_INFO "CARD_BUS_CLK_RUN |");
++ break;
++ case STATUS_BUF_READ_RDY:
++ printk(KERN_INFO "BUF_READ_RDY |");
++ break;
++ case STATUS_BUF_WRITE_RDY:
++ printk(KERN_INFO "BUF_WRITE_RDY |");
++ break;
++ case STATUS_RESP_CRC_ERR:
++ printk(KERN_INFO "RESP_CRC_ERR |");
++ break;
++ case STATUS_TIME_OUT_RESP:
++ printk(KERN_INFO "TIME_OUT_RESP |");
++ break;
++ case STATUS_TIME_OUT_READ:
++ printk(KERN_INFO "TIME_OUT_READ |");
++ break;
++ default:
++ printk(KERN_INFO "Invalid Status Register value0x%x\n",
++ bitset);
++ break;
++ }
++ sts &= ~bitset;
++ }
++ printk(KERN_INFO "\n");
++}
++static void sdhc_dumpregs(struct sdhc_host *host)
++{
++ printk(KERN_DEBUG DRIVER_NAME ": ========= REGISTER DUMP ==========\n");
++ printk(KERN_DEBUG DRIVER_NAME ": Clock Control Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_STR_STP_CLK));
++ printk(KERN_DEBUG DRIVER_NAME ": Status Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_STATUS));
++ printk(KERN_DEBUG DRIVER_NAME ": Clock Rate Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_CLK_RATE));
++ printk(KERN_DEBUG DRIVER_NAME
++ ": Command and data Control Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_CMD_DAT_CONT));
++ printk(KERN_DEBUG DRIVER_NAME
++ ": Response and Timeout Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_RES_TO));
++ printk(KERN_DEBUG DRIVER_NAME ": Read Timeout Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_READ_TO));
++ printk(KERN_DEBUG DRIVER_NAME ": Block Length Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_BLK_LEN));
++ printk(KERN_DEBUG DRIVER_NAME ": Number of Blocks Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_NOB));
++ printk(KERN_DEBUG DRIVER_NAME ": Revision Number Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_REV_NO));
++ printk(KERN_DEBUG DRIVER_NAME ": Interrupt Control Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_INT_CNTR));
++ printk(KERN_DEBUG DRIVER_NAME ": Command Number Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_CMD));
++ printk(KERN_DEBUG DRIVER_NAME ": Command Argument Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_ARG));
++ printk(KERN_DEBUG DRIVER_NAME ": Command Response Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_RES_FIFO));
++ printk(KERN_DEBUG DRIVER_NAME
++ ": Data Buffer Access Register : 0x%08x\n",
++ fsl_readl(host->ioaddr + MMC_BUFFER_ACCESS));
++}
++#endif
++
++
++static int sdhc_data_done(struct sdhc_host *host, unsigned int stat);
++
++static void fsl_writel(u32 val, unsigned __iomem *addr)
++{
++ out_be32(addr, val);
++}
++
++static inline u32 fsl_readl(unsigned __iomem *addr)
++{
++ return in_be32(addr);
++}
++static void mpc5121_sdhc_io_pullup_d3_cd(void)
++{
++ struct device_node *np;
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-ioctl");
++ if (np) {
++ void __iomem *ioctl = of_iomap(np, 0);
++ fsl_writel(H2_SDHC_D3_CD | DATA_SKEW_RATE_STD_4 | PU_ENABLE,
++ ioctl + D3_CD_LINE);
++ iounmap(ioctl);
++ }
++}
++
++
++static void mpc5121_sdhc_io_pulldown_d3_cd(void)
++{
++ struct device_node *np;
++ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-ioctl");
++ if (np) {
++ void __iomem *ioctl = of_iomap(np, 0);
++ fsl_writel(H2_SDHC_D3_CD | DATA_SKEW_RATE_STD_4 | PD_ENABLE,
++ ioctl + D3_CD_LINE);
++ iounmap(ioctl);
++ }
++}
++
++/*!
++ *This function resets the SDHC host.
++ *
++ * @param host Pointer to MMC/SD host structure
++ */
++static void sdhc_softreset(struct sdhc_host *host)
++{
++ /* reset sequence */
++
++ fsl_writel(0x8, host->ioaddr + MMC_STR_STP_CLK);
++ fsl_writel(0x9, host->ioaddr + MMC_STR_STP_CLK);
++ fsl_writel(0x1, host->ioaddr + MMC_STR_STP_CLK);
++ fsl_writel(0x1, host->ioaddr + MMC_STR_STP_CLK);
++ fsl_writel(0x1, host->ioaddr + MMC_STR_STP_CLK);
++ fsl_writel(0x1, host->ioaddr + MMC_STR_STP_CLK);
++ fsl_writel(0x1, host->ioaddr + MMC_STR_STP_CLK);
++ fsl_writel(0x1, host->ioaddr + MMC_STR_STP_CLK);
++ fsl_writel(0x1, host->ioaddr + MMC_STR_STP_CLK);
++ fsl_writel(0x1, host->ioaddr + MMC_STR_STP_CLK);
++ fsl_writel(0x3f, host->ioaddr + MMC_CLK_RATE);
++
++ fsl_writel(0xff, host->ioaddr + MMC_RES_TO);
++ fsl_writel(512, host->ioaddr + MMC_BLK_LEN);
++ fsl_writel(1, host->ioaddr + MMC_NOB);
++#ifndef CONFIG_MMC_MPC5121_USE_CARD_INSERTION_INT
++ mpc5121_sdhc_io_pullup_d3_cd();
++#endif
++
++}
++#ifdef CONFIG_MMC_MPC5121_USE_DMA
++/*!
++ * After DMA completion during read operation this gets called in the DMA isr.
++ * @param host pointer to host data structure
++ */
++static int dma_read_over(struct sdhc_host *host)
++{
++ unsigned int status = 0;
++ struct mmc_data *data = host->data;
++
++ status = fsl_readl(host->ioaddr + MMC_STATUS);
++ if (status & STATUS_TIME_OUT_READ) {
++ pr_debug("%s: Read time out occurred\n", DRIVER_NAME);
++ data->error = -ETIMEDOUT;
++ fsl_writel(STATUS_TIME_OUT_READ,
++ host->ioaddr + MMC_STATUS);
++ } else if (status & STATUS_READ_CRC_ERR) {
++ pr_debug("%s: Read CRC error occurred\n", DRIVER_NAME);
++ data->error = -EILSEQ;
++ fsl_writel(STATUS_READ_CRC_ERR,
++ host->ioaddr + MMC_STATUS);
++ }
++ fsl_writel(STATUS_READ_OP_DONE, host->ioaddr + MMC_STATUS);
++
++ sdhc_data_done(host, status);
++ return 1 ;
++
++}
++
++/*!
++ * After DMA completion during write operation this gets called in the DMA isr.
++ * @param host pointer to host data structure
++ */
++static int dma_write_over(struct sdhc_host *host)
++{
++ unsigned int count, status = 0;
++ struct mmc_data *data = host->data;
++ count = 0;
++
++ while (!(fsl_readl(host->ioaddr + MMC_STATUS)
++ & STATUS_WRITE_OP_DONE)) {
++ count++;
++ if (count > 100000) {
++ printk(KERN_ERR "%s: "
++ "failed to get WRITE_OP_DONE\n",
++ DRIVER_NAME);
++ break;
++ }
++ }
++
++ ;
++
++ /* check for CRC errors */
++ status = fsl_readl(host->ioaddr + MMC_STATUS);
++ if (status & STATUS_WRITE_CRC_ERR) {
++ pr_debug("%s: Write CRC error occurred\n", DRIVER_NAME);
++
++ data->error = -EILSEQ;
++ fsl_writel(STATUS_WRITE_CRC_ERR,
++ host->ioaddr + MMC_STATUS);
++ }
++ fsl_writel(STATUS_WRITE_OP_DONE, host->ioaddr + MMC_STATUS);
++ /* complete the data transfer request */
++ sdhc_data_done(host, status);
++ return 1;
++}
++
++/*!
++ * DMA completion callback routine, this gets called in the DMA isr, when
++ * DMA is over the sleeping process is woken up.
++ * @param error_status error info of DMA transfer
++ */
++static void fsl_dma_sdhc_callback(void *arg, int error_status)
++{
++ struct sdhc_host *host = (struct sdhc_host *)arg;
++ struct mmc_data *data = host->data;
++
++
++ unsigned long *buf;
++ buf = (unsigned long *)((u32)page_address((void *)data->sg->page_link)
++ + (u32) data->sg->offset);
++
++ if (!error_status) {
++ if ((data->flags&MMC_DATA_READ)) {
++ dma_correction((unsigned long *)write_buf,
++ buf, host->dma_size);
++ dma_read_over(host);
++ return ;
++ } /* This is MMC_DATA_WRITE operation */
++ else {
++ dma_write_over(host);
++ return;
++ }
++ } else /* There was an error during DMA operation */
++ printk(KERN_ERR "DMA error on SDHC channel\n");
++}
++
++
++/*!
++ * Allocate buffer memory for DMA transfer
++ * Request for DMA channel
++ * and initialize the wait queue
++ * @param host pointer to MMC/SD host structure
++ */
++static int fsl_sdhc_dma_init(struct sdhc_host *host)
++{
++ /*
++ * Allocate and setup the DMA channels
++ */
++ int dma_chan;
++ dma_chan = fsl_dma_chan_request(MPC512X_DMA_SDHC);
++ if (dma_chan < 0) {
++ printk(KERN_ERR "couldn't get SDHC DMA channel\n");
++ host->dma_available = 0;
++ return -ENOMEM;
++ }
++ fsl_dma_callback_set(dma_chan, fsl_dma_sdhc_callback, host);
++
++ write_buf = dma_alloc_coherent(NULL, sizeof(u32) * 1024,
++ &sphyaddr, GFP_KERNEL);
++ if (!write_buf)
++ return -ENOMEM;
++ return 0;
++}
++
++/*!
++ * config information for DMA. The DMA transfer is between SDHC FIFO
++ * and the DMA coherent buffer initialized in the beginning.
++ * @param host pointer to MMC/SD host data structure
++ * @param data pointer to MMC Data structure
++ * @param MMC_OP operation - to or from SD FIFO
++ * @param len data transfer length
++ */
++static int fsl_dma_priv_config(struct sdhc_host *host, struct mmc_data *data,
++ int MMC_OP, int len)
++{
++ static struct fsl_dma_requestbuf dma_priv;
++ /* DMA_FROM_DEVICE = read the card by host*/
++ if (MMC_OP == DMA_TO_DEVICE) {
++ dma_priv.src = (dma_addr_t)(sphyaddr);
++ dma_priv.soff = 4;
++ dma_priv.dest = (dma_addr_t)host->addr + MMC_BUFFER_ACCESS;
++ dma_priv.doff = 0;
++ dma_priv.minor_loop = 16;
++ } else {
++ dma_priv.src = (dma_addr_t) host->addr + MMC_BUFFER_ACCESS;
++ dma_priv.soff = 0;
++ dma_priv.dest = (dma_addr_t)(sphyaddr) ;
++ dma_priv.doff = 4;
++ dma_priv.minor_loop = 16;
++ }
++ host->dma = &dma_priv;
++ return 1;
++}
++
++/*!
++ * function to enable byte swap operation whenever data is written or
++ * read from FIFO so this fuction is called before DMA write and after
++ * DMA read operation.
++ * @params pointers to the two buffers
++ * @param len the length of data in bytes
++ */
++static void dma_correction(unsigned long *buf, unsigned long *temp_buf,
++ int len)
++{
++ int i;
++ unsigned long temp_data;
++
++ for (i = 0; i < ((len+3)/4); i++) {
++ temp_data = *(buf+i);
++ temp_data = cpu_to_le32(temp_data);
++ *(temp_buf+i) = temp_data;
++ }
++}
++
++#endif
++
++/* Wait count to start the clock */
++#define CMD_WAIT_CNT 1000
++
++/*!
++ * This function sets the SDHC register to stop the clock and waits for the
++ * clock stop indication.
++ *
++ * @param host Pointer to MMC/SD host structure
++ * @param wait Boolean value to indicate whether to wait
++ * for the clock to start or come out instantly
++ */
++static void sdhc_stop_clock(struct sdhc_host *host, bool wait)
++{
++ int wait_cnt = 0;
++ while (1) {
++ fsl_writel(STR_STP_CLK_STOP_CLK,
++ host->ioaddr + MMC_STR_STP_CLK);
++
++
++ if (!wait)
++ break;
++
++ wait_cnt = CMD_WAIT_CNT;
++
++ while (wait_cnt--) {
++ if (!(fsl_readl(host->ioaddr + MMC_STATUS) &
++ STATUS_CARD_BUS_CLK_RUN))
++ break;
++ }
++ if (!(fsl_readl(host->ioaddr + MMC_STATUS) &
++ STATUS_CARD_BUS_CLK_RUN))
++ break;
++ }
++}
++
++/*!
++ * This function sets the SDHC register to start the clock and waits for the
++ * clock start indication. When the clock starts SDHC module starts processing
++ * the command in CMD Register with arguments in ARG Register.
++ *
++ * @param host Pointer to MMC/SD host structure
++ * @param wait Boolean value to indicate whether to wait for the
++ * clock to start or come out instantly
++ */
++static void sdhc_start_clock(struct sdhc_host *host, bool wait)
++{
++ int wait_cnt;
++ if (fsl_readl(host->ioaddr + MMC_STATUS) & STATUS_CARD_BUS_CLK_RUN)
++ return;
++
++ while (1) {
++ setbits32(host->ioaddr + MMC_STR_STP_CLK,
++ STR_STP_CLK_START_CLK);
++ if (!wait)
++ break;
++
++ wait_cnt = CMD_WAIT_CNT;
++ while (wait_cnt--) {
++ if (!(fsl_readl(host->ioaddr + MMC_STATUS) &
++ STATUS_CARD_BUS_CLK_RUN))
++ setbits32(host->ioaddr + MMC_STR_STP_CLK,
++ STR_STP_CLK_START_CLK);
++
++ }
++ if (fsl_readl(host->ioaddr + MMC_STATUS) &
++ STATUS_CARD_BUS_CLK_RUN)
++ break;
++ }
++}
++
++/*!
++ * This function is called to setup SDHC register for data transfer.
++ * The function allocates DMA buffers, configures the DMA channel.
++ * Start the DMA channel to transfer data. When DMA is not enabled this
++ * function set ups only Number of Block and Block Length registers.
++ *
++ * @param host Pointer to MMC/SD host structure
++ * @param data Pointer to MMC/SD data structure
++ */
++static void sdhc_setup_data(struct sdhc_host *host, struct mmc_data *data)
++{
++ unsigned int nob = data->blocks;
++
++ if (data->flags & MMC_DATA_STREAM)
++ nob = 0xffff;
++
++ host->data = data;
++
++ fsl_writel(nob, host->ioaddr + MMC_NOB);
++ fsl_writel(data->blksz, host->ioaddr + MMC_BLK_LEN);
++
++ host->dma_size = data->blocks * data->blksz;
++ pr_debug("%s:Request bytes to transfer:%d\n", DRIVER_NAME,
++ host->dma_size);
++}
++
++/*!
++ * This function is called by \b fslmci_request() function to setup the SDHC
++ * register to issue command. This function disables the card insertion and
++ * removal detection interrupt.
++ *
++ * @param host Pointer to MMC/SD host structure
++ * @param cmd Pointer to MMC/SD command structure
++ * @param cmdat Value to store in Command and Data Control Register
++ */
++static void sdhc_start_cmd(struct sdhc_host *host, struct mmc_command *cmd,
++ unsigned int cmdat)
++{
++ WARN_ON(host->cmd != NULL);
++ fsl_writel(INT_CNTR_END_CMD_RES, host->ioaddr + MMC_INT_CNTR);
++
++ host->cmd = cmd;
++
++ switch (RSP_TYPE(mmc_resp_type(cmd))) {
++ case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6 */
++ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1;
++ break;
++ case RSP_TYPE(MMC_RSP_R3):
++ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3;
++ break;
++ case RSP_TYPE(MMC_RSP_R2):
++ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2;
++ break;
++ default:
++ /* No Response required */
++ break;
++ }
++
++ if (cmd->opcode == MMC_GO_IDLE_STATE)
++ cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */
++
++ if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4)
++ cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
++ fsl_writel(cmd->opcode, host->ioaddr + MMC_CMD);
++ fsl_writel(cmd->arg, host->ioaddr + MMC_ARG);
++
++ fsl_writel(cmdat, host->ioaddr + MMC_CMD_DAT_CONT);
++ sdhc_start_clock(host, true);
++}
++
++/*!
++ * This function is called to complete the command request.
++ * This function enables insertion or removal interrupt.
++ *
++ * @param host Pointer to MMC/SD host structure
++ * @param req Pointer to MMC/SD command request structure
++ */
++static void sdhc_finish_request(struct sdhc_host *host,
++ struct mmc_request *req)
++{
++ u32 intr_enable;
++ host->mrq = NULL;
++ host->cmd = NULL;
++ host->data = NULL;
++
++
++ mmc_request_done(host->mmc, req);
++ intr_enable = (INT_CNTR_END_CMD_RES | INT_CNTR_CARD_INSERTION_EN
++ | INT_CNTR_CARD_REMOVAL_EN);
++ fsl_writel(intr_enable, host->ioaddr + MMC_INT_CNTR);
++}
++
++/*!
++ * This function is called when the requested command is completed.
++ * This function reads the response from the card and data if the command
++ * is for data transfer. This function checks for CRC error in response FIFO or
++ * data FIFO.
++ *
++ * @param host Pointer to MMC/SD host structure
++ * @param stat Content of SDHC Status Register
++ *
++ * @return This function returns 0 if there is no pending command, otherwise 1
++ * always.
++ */
++static int sdhc_cmd_done(struct sdhc_host *host, unsigned int stat)
++{
++ struct mmc_command *cmd = host->cmd;
++ struct mmc_data *data = host->data;
++ struct scatterlist *sg;
++ int i, count;
++ u32 a, b, c;
++ u32 temp_data;
++ unsigned int status = 0;
++ unsigned long *buf;
++ int no_of_bytes;
++ int no_of_words;
++ int num_buf = 1;
++
++ if (!cmd) {
++ /* There is no command for completion */
++ return 0;
++ }
++
++ /* As this function finishes the command, initialize cmd to NULL */
++ host->cmd = NULL;
++
++ /* check for Time out errors */
++ if (stat & STATUS_TIME_OUT_RESP) {
++ fsl_writel(STATUS_TIME_OUT_RESP, host->ioaddr + MMC_STATUS);
++ pr_debug("%s: CMD TIMEOUT\n", DRIVER_NAME);
++ cmd->error = -ETIMEDOUT;
++ } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
++ fsl_writel(STATUS_RESP_CRC_ERR, host->ioaddr + MMC_STATUS);
++ cmd->error = -EILSEQ;
++ }
++
++ /* Read response from the card */
++ switch (RSP_TYPE(mmc_resp_type(cmd))) {
++ case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6 */
++ a = fsl_readl(host->ioaddr + MMC_RES_FIFO) & 0xffff;
++ b = fsl_readl(host->ioaddr + MMC_RES_FIFO) & 0xffff;
++ c = fsl_readl(host->ioaddr + MMC_RES_FIFO) & 0xffff;
++
++ cmd->resp[0] = a << 24 | b << 8 | c >> 8;
++ break;
++ case RSP_TYPE(MMC_RSP_R3): /* r3, r4 */
++ a = fsl_readl(host->ioaddr + MMC_RES_FIFO) & 0xffff;
++ b = fsl_readl(host->ioaddr + MMC_RES_FIFO) & 0xffff;
++ c = fsl_readl(host->ioaddr + MMC_RES_FIFO) & 0xffff;
++ cmd->resp[0] = a << 24 | b << 8 | c >> 8;
++
++ break;
++ case RSP_TYPE(MMC_RSP_R2):
++ for (i = 0; i < 4; i++) {
++ a = fsl_readl(host->ioaddr + MMC_RES_FIFO) & 0xffff;
++ b = fsl_readl(host->ioaddr + MMC_RES_FIFO) & 0xffff;
++ cmd->resp[i] = a << 16 | b;
++
++ }
++ break;
++ default:
++ break;
++ }
++
++ pr_debug("%s: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", DRIVER_NAME,
++ cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
++
++ if (!host->data || cmd->error) {
++ /* complete the command */
++ sdhc_finish_request(host, host->mrq);
++#ifndef CONFIG_MMC_MPC5121_USE_CARD_INSERTION_INT
++ mmc_detect_change(host->mmc, msecs_to_jiffies(100));
++#endif
++ return 1;
++ }
++
++ /* The command has a data transfer */
++ no_of_bytes = data->blocks * data->blksz;
++ host->dma_size = no_of_bytes;
++ buf = (unsigned long *)((u32)page_address((void *)data->sg->page_link) +
++ (u32) data->sg->offset);
++ sg = data->sg ;
++
++ /* calculate the number of bytes requested for transfer */
++ no_of_words = (no_of_bytes + 3) / 4;
++ pr_debug("no_of_words=%d\n", no_of_words);
++
++
++#ifdef CONFIG_MMC_MPC5121_USE_DMA
++ if (host->dma_size < (16 << host->mmc->ios.bus_width))
++ goto pio;
++
++ if ((data->flags & MMC_DATA_READ)) {
++ fsl_dma_priv_config(host, data, DMA_FROM_DEVICE, no_of_bytes);
++ host->dma->len = no_of_bytes ;
++ fsl_dma_config(MPC512X_DMA_SDHC, (host->dma), num_buf);
++
++ fsl_dma_enable(MPC512X_DMA_SDHC);
++ return 1;
++ }
++ if (data->flags & MMC_DATA_WRITE) {
++ dma_correction(buf, (unsigned long *)write_buf, host->dma_size);
++ fsl_dma_priv_config(host, data, DMA_TO_DEVICE, no_of_bytes);
++ host->dma->len = no_of_bytes ;
++ fsl_dma_config(MPC512X_DMA_SDHC, (host->dma), num_buf);
++ fsl_dma_enable(MPC512X_DMA_SDHC);
++ return 1;
++ }
++pio:
++#endif
++ /* Use PIO tranfer of data */
++ if (data->flags & MMC_DATA_READ) {
++ for (i = 0; i < no_of_words; i++) {
++ /* wait for buffers to be ready for read */
++
++ count = 0;
++ while (!(fsl_readl(host->ioaddr + MMC_STATUS) &
++ (STATUS_BUF_READ_RDY |
++ STATUS_READ_OP_DONE))) {
++ count++;
++ if (count > 100000) {
++ printk(KERN_ERR "%s: "
++ "failed to get READ_OP_DONE\n",
++ DRIVER_NAME);
++ break;
++ }
++ }
++
++ ;
++
++ /* read 32 bit data */
++ temp_data = fsl_readl(host->ioaddr + MMC_BUFFER_ACCESS);
++ temp_data = cpu_to_le32(temp_data);
++ if (no_of_bytes >= 4) {
++ *buf++ = temp_data;
++ no_of_bytes -= 4;
++ }
++ }
++
++ count = 0;
++ /* wait for read operation completion bit */
++ while (!(fsl_readl(host->ioaddr + MMC_STATUS)
++ & STATUS_READ_OP_DONE)) {
++ count++;
++ if (count > 100000) {
++ printk(KERN_ERR "%s: "
++ "failed to get READ_OP_DONE\n",
++ DRIVER_NAME);
++ break;
++ }
++ }
++
++ ;
++ /* check for time out and CRC errors */
++ status = fsl_readl(host->ioaddr + MMC_STATUS);
++ if (status & STATUS_TIME_OUT_READ) {
++ pr_debug("%s: Read time out occurred\n", DRIVER_NAME);
++ data->error = -ETIMEDOUT;
++ fsl_writel(STATUS_TIME_OUT_READ,
++ host->ioaddr + MMC_STATUS);
++ } else if (status & STATUS_READ_CRC_ERR) {
++ pr_debug("%s: Read CRC error occurred\n", DRIVER_NAME);
++ data->error = -EILSEQ;
++ fsl_writel(STATUS_READ_CRC_ERR,
++ host->ioaddr + MMC_STATUS);
++ }
++ fsl_writel(STATUS_READ_OP_DONE, host->ioaddr + MMC_STATUS);
++
++ pr_debug("%s: Read %u words\n", DRIVER_NAME, i);
++
++ sdhc_data_done(host, status);
++ return 1;
++ }
++ if (data->flags & MMC_DATA_WRITE) {
++ for (i = 0; i < no_of_words; i++) {
++
++ /* wait for buffers to be ready for write */
++ while (!(fsl_readl(host->ioaddr + MMC_STATUS) &
++ STATUS_BUF_WRITE_RDY)) ;
++
++ /* write 32 bit data */
++ /* ALLGO BUGFIX: MMC data is LE */
++ fsl_writel(cpu_to_le32(*buf++),
++ host->ioaddr + MMC_BUFFER_ACCESS);
++
++ if (fsl_readl(host->ioaddr + MMC_STATUS)
++ & STATUS_WRITE_OP_DONE)
++ break;
++ }
++
++ /* wait for write operation completion bit */
++ while (!(fsl_readl(host->ioaddr + MMC_STATUS) &
++ STATUS_WRITE_OP_DONE))
++ ;
++
++ /* check for CRC errors */
++ status = fsl_readl(host->ioaddr + MMC_STATUS);
++ if (status & STATUS_WRITE_CRC_ERR) {
++ pr_debug("%s: Write CRC error occurred\n", DRIVER_NAME);
++
++ data->error = -EILSEQ;
++ fsl_writel(STATUS_WRITE_CRC_ERR,
++ host->ioaddr + MMC_STATUS);
++ }
++ fsl_writel(STATUS_WRITE_OP_DONE, host->ioaddr + MMC_STATUS);
++ pr_debug("%s: Written %u words\n", DRIVER_NAME, i);
++
++ }
++
++ /* complete the data transfer request */
++ sdhc_data_done(host, status);
++ return 1;
++}
++
++
++/*!
++ * This function is called when the data transfer is completed either by DMA
++ * or by core. This function is called to clean up the DMA buffer and to send
++ * STOP transmission command for commands to transfer data. This function
++ * completes request issued by the MMC/SD core driver.
++ *
++ * @param host pointer to MMC/SD host structure.
++ * @param stat content of SDHC Status Register
++ *
++ * @return This function returns 0 if no data transfer otherwise return 1
++ * always.
++ */
++static int sdhc_data_done(struct sdhc_host *host, unsigned int stat)
++{
++ struct mmc_data *data = host->data;
++
++ if (!data)
++ return 0;
++#ifdef CONFIG_MMC_MPC5121_USE_DMA
++ if (host->dma_size > (16 << host->mmc->ios.bus_width))
++ fsl_dma_disable(MPC512X_DMA_SDHC);
++
++#endif
++ if (fsl_readl(host->ioaddr + MMC_STATUS) & STATUS_ERR_MASK) {
++ pr_debug("%s: request failed. status: 0x%08x\n",
++ DRIVER_NAME, fsl_readl(host->ioaddr + MMC_STATUS));
++ }
++
++ host->data = NULL;
++ data->bytes_xfered = host->dma_size;
++
++ if (host->mrq->stop && (data->error == 0)) {
++ sdhc_start_cmd(host, host->mrq->stop, 0);
++ } else {
++ sdhc_finish_request(host, host->mrq);
++ }
++
++ return 1;
++}
++
++
++static void sdhc_set_power(struct sdhc_host *host, unsigned short power)
++{
++
++ if (host->power == power)
++ return;
++
++ if (power == (unsigned short)-1)
++ host->power = power;
++}
++
++/*!
++ * This function is called by MMC/SD Bus Protocol driver to issue a MMC
++ * and SD commands to the SDHC.
++ *
++ * @param mmc Pointer to MMC/SD host structure
++ * @param mrq Pointer to MMC/SD command request structure
++ */
++static void sdhc_request(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++ struct sdhc_host *host = mmc_priv(mmc);
++ /* Holds the value of Command and Data Control Register */
++ unsigned long cmdat;
++
++ WARN_ON(host->mrq != NULL);
++
++ host->mrq = mrq;
++#ifdef CONFIG_MMC_DEBUG
++ dump_cmd(req->cmd);
++ dump_status(__FUNCTION__, __raw_readl(host->base + MMC_STATUS));
++#endif
++
++ cmdat = 0;
++ if (mrq->data) {
++ sdhc_setup_data(host, mrq->data);
++
++ cmdat |= CMD_DAT_CONT_DATA_ENABLE;
++
++ if (mrq->data->flags & MMC_DATA_WRITE)
++ cmdat |= CMD_DAT_CONT_WRITE;
++
++ if (mrq->data->flags & MMC_DATA_STREAM)
++ printk(KERN_ERR
++ "FSL MMC does not support stream mode\n");
++ }
++ sdhc_start_cmd(host, mrq->cmd, cmdat);
++}
++
++/*!
++ * This function is called by MMC/SD Bus Protocol driver to change the clock
++ * speed of MMC or SD card
++ *
++ * @param mmc Pointer to MMC/SD host structure
++ * @param ios Pointer to MMC/SD I/O type structure
++ */
++static void sdhc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++ struct sdhc_host *host = mmc_priv(mmc);
++ /*This variable holds the value of clock prescaler */
++ int prescaler;
++ int clk_rate = clk_get_rate(host->sdhc_clk);
++ if (ios->power_mode == MMC_POWER_OFF)
++ sdhc_set_power(host, -1);
++ else
++ sdhc_set_power(host, ios->vdd);
++
++ if (ios->clock) {
++ unsigned int clk_dev = 0;
++
++ if (ios->clock == mmc->f_min)
++ prescaler = 16;
++ else
++ prescaler = 0;
++
++ while (prescaler <= 0x800) {
++ for (clk_dev = 1; clk_dev <= 0xF; clk_dev++) {
++ int x;
++ if (prescaler != 0) {
++ x = (clk_rate / (clk_dev + 1)) /
++ (prescaler * 2);
++ } else {
++ x = clk_rate / (clk_dev + 1);
++ }
++
++ pr_debug("x=%d, clock=%d %d\n", x, ios->clock,
++ clk_dev);
++ if (x <= ios->clock)
++ break;
++ }
++ if (clk_dev < 0x10)
++ break;
++ if (prescaler == 0)
++ prescaler = 1;
++ else
++ prescaler <<= 1;
++ }
++
++ pr_debug("prescaler = 0x%x, divider = 0x%x\n", prescaler,
++ clk_dev);
++ sdhc_stop_clock(host, true);
++
++ fsl_writel((prescaler << 4) | clk_dev,
++ host->ioaddr + MMC_CLK_RATE);
++ sdhc_start_clock(host, false);
++ } else {
++ sdhc_stop_clock(host, true);
++ }
++}
++
++/*!
++ * MMC/SD host operations structure.
++ * These functions are registered with MMC/SD Bus protocol driver.
++ */
++static const struct mmc_host_ops sdhc_ops = {
++ .request = sdhc_request,
++ .set_ios = sdhc_set_ios,
++};
++
++/*!
++ * Interrupt service routine registered to handle the SDHC interrupts.
++ * This interrupt routine handles end of command, card insertion and
++ * card removal interrupts. If the interrupt is card insertion or removal then
++ * inform the MMC/SD core driver to detect the change in physical connections.
++ * If the command is END_CMD_RESP read the Response FIFO.
++ *
++ * @param irq the interrupt number
++ * @param devid driver private data
++ * @param regs holds a snapshot of the processor's context before the
++ * processor entered the interrupt code
++ *
++ * @return The function returns \b IRQ_RETVAL(1) if interrupt was handled,
++ * returns \b IRQ_RETVAL(0) if the interrupt was not handled.
++ */
++static irqreturn_t sdhc_irq(int irq, void *dev_id)
++{
++ struct sdhc_host *host = dev_id;
++ irqreturn_t result = IRQ_HANDLED;
++ unsigned int status = 0;
++
++ status = fsl_readl(host->ioaddr + MMC_STATUS);
++ if (status & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL)) {
++ if (status & STATUS_CARD_INSERTION)
++ fsl_writel(STATUS_CARD_INSERTION,
++ host->ioaddr + MMC_STATUS);
++ if (status & STATUS_CARD_REMOVAL)
++ fsl_writel(STATUS_CARD_REMOVAL,
++ host->ioaddr + MMC_STATUS);
++ mmc_detect_change(host->mmc, msecs_to_jiffies(100));
++
++ }
++
++ if (status & STATUS_END_CMD_RESP) {
++ setbits32(host->ioaddr + MMC_STATUS,
++ STATUS_END_CMD_RESP);
++ sdhc_cmd_done(host, status);
++
++ }
++ return result;
++}
++
++
++/*****************************************************************************\
++ * *
++ * Device probing/removal *
++ * *
++\*****************************************************************************/
++
++static void sdhc_remove_slot(struct of_device *ofdev, int slot)
++{
++ struct sdhc_chip *chip;
++ struct mmc_host *mmc;
++ struct sdhc_host *host;
++
++ chip = dev_get_drvdata(&(ofdev->dev));
++ host = chip->hosts[slot];
++ mmc = host->mmc;
++
++ chip->hosts[slot] = NULL;
++ mmc_remove_host(mmc);
++ sdhc_softreset(host);
++
++ free_irq(host->irq, host);
++
++ iounmap(host->ioaddr);
++
++ release_mem_region(host->addr, host->size);
++
++ mmc_free_host(mmc);
++}
++
++#if CONFIG_PPC_MPC5125
++#define SDHC1_IO_ADDR_BASE (0x8000a000+0x6f)
++static sdhc_io_init(void)
++{
++ unsigned char *sdhc_io_reg;
++ unsigned int i=6;
++ sdhc_io_reg=ioremap(SDHC1_IO_ADDR_BASE, 0x6);
++ for(i=0;i<6;i++)
++ {
++ sdhc_io_reg[i]=0x1b;
++ }
++ iounmap(sdhc_io_reg);
++}
++#endif
++static int __devinit sdhc_probe_slot(struct of_device *ofdev, int slot)
++{
++ struct device_node *np = ofdev->node;
++ struct device_node *cpu;
++ int ret;
++ struct sdhc_chip *chip;
++ struct mmc_host *mmc;
++ struct sdhc_host *host;
++ struct resource res;
++ u32 intr_enable;
++
++ chip = dev_get_drvdata(&(ofdev->dev));
++ BUG_ON(!chip);
++
++ mmc = mmc_alloc_host(sizeof(struct sdhc_host), &(ofdev->dev));
++ if (!mmc)
++ return -ENOMEM;
++
++ host = mmc_priv(mmc);
++ host->mmc = mmc;
++
++ host->chip = chip;
++ chip->hosts[slot] = host;
++
++ ret = of_address_to_resource(np, 0, &res);
++ if (ret)
++ goto free;
++ host->addr = res.start;
++
++ host->size = res.end - res.start + 1;
++ host->irq = irq_of_parse_and_map(np, 0);
++ printk(KERN_DEBUG "slot %d at 0x%08lx, irq %d and size = %x\n",
++ slot, host->addr, host->irq, host->size);
++
++ snprintf(host->slot_descr, 20, "sdhc:slot%d", slot);
++
++ if (!request_mem_region(host->addr, host->size, DRIVER_NAME)) {
++ ret = -EBUSY;
++ goto release;
++ }
++#if CONFIG_PPC_MPC5125
++ sdhc_io_init();
++#endif
++ host->ioaddr = ioremap(host->addr, host->size);
++ if (!host->ioaddr) {
++ ret = -ENOMEM;
++ goto release;
++ }
++ host->sdhc_clk = clk_get(&ofdev->dev, "sdhc_clk");
++ clk_enable(host->sdhc_clk);
++ sdhc_softreset(host);
++#ifdef CONFIG_MMC_MPC5121_USE_DMA
++ fsl_sdhc_dma_init(host);
++#endif
++ fsl_writel(READ_TO_VALUE, host->ioaddr + MMC_READ_TO);
++ intr_enable = (INT_CNTR_END_CMD_RES | INT_CNTR_CARD_INSERTION_EN
++ | INT_CNTR_CARD_REMOVAL_EN);
++ fsl_writel(intr_enable, host->ioaddr + MMC_INT_CNTR);
++ cpu = of_find_node_by_type(NULL, "cpu");
++ if (cpu) {
++ unsigned int size;
++ const u32 *prop = of_get_property(cpu, "bus-frequency", &size);
++ host->max_clk = *prop;
++ of_node_put(cpu);
++ } else
++ host->max_clk = 396000000;
++ mmc->ops = &sdhc_ops;
++ mmc->f_min = 300000;
++ mmc->f_max = min((int)host->max_clk, 25000000);
++ mmc->caps = MMC_CAP_4_BIT_DATA;
++ mmc->ocr_avail = MMC_VDD_32_33 |
++ MMC_VDD_33_34 |
++ MMC_VDD_29_30 |
++ MMC_VDD_30_31 |
++ MMC_VDD_165_195;
++ spin_lock_init(&host->lock);
++ /*
++ * Maximum number of segments. Hardware cannot do scatter lists.
++ */
++
++#ifdef CONFIG_MMC_DEBUG
++ sdhc_dumpregs(host);
++#endif
++ ret = request_irq(host->irq, sdhc_irq, IRQF_SHARED,
++ host->slot_descr, host);
++ if (ret)
++ goto release;
++ mmiowb();
++ mmc_add_host(mmc);
++ printk(KERN_INFO "%s: SDHC at 0x%08lx irq %d %s\n", mmc_hostname(mmc),
++ host->addr, host->irq,
++ (host->flags & SDHC_USE_DMA)?"DMA":"PIO");
++ return 0;
++release:
++ release_mem_region(host->addr, host->size);
++free:
++ mmc_remove_host(mmc);
++ return ret;
++}
++
++
++static int __devinit sdhc_probe(struct of_device *ofdev,
++ const struct of_device_id *match)
++{
++ int ret = 1, i;
++ u8 slots;
++ struct sdhc_chip *chip;
++ BUG_ON(ofdev == NULL);
++ BUG_ON(match == NULL);
++ slots = SDHC_SLOTS_NUMBER;
++ DBG("found %d slot(s)", slots);
++ if (slots == 0)
++ return -ENODEV;
++ chip = kmalloc(sizeof(struct sdhc_chip) +
++ sizeof(struct sdhc_host *) * slots, GFP_KERNEL);
++ if (!chip) {
++ ret = -ENOMEM;
++ goto err;
++ }
++ chip->ofdev = ofdev;
++ chip->num_slots = slots;
++ dev_set_drvdata(&(ofdev->dev), chip);
++ for (i = 0; i < slots; i++) {
++ ret = 0;
++ ret = sdhc_probe_slot(ofdev, i);
++ if (ret) {
++ for (i--; i >= 0; i--)
++ sdhc_remove_slot(ofdev, i);
++ goto free;
++ }
++ }
++ return 0;
++free:
++ dev_set_drvdata(&(ofdev->dev), NULL);
++ kfree(chip);
++err:
++ return ret;
++}
++
++static int __devexit sdhc_remove(struct of_device *ofdev)
++{
++ int i;
++ struct sdhc_chip *chip;
++ chip = dev_get_drvdata(&(ofdev->dev));
++ if (chip) {
++ for (i = 0; i < chip->num_slots; i++)
++ sdhc_remove_slot(ofdev, i);
++ dev_set_drvdata(&(ofdev->dev), NULL);
++ kfree(chip);
++ mpc5121_sdhc_io_pulldown_d3_cd();
++#ifdef CONFIG_MMC_MPC5121_USE_DMA
++ fsl_dma_free_chan(MPC512X_DMA_SDHC);
++ dma_free_coherent(NULL, sizeof(u32) * 1024, write_buf,
++ sphyaddr);
++#endif
++ }
++ return 0;
++}
++
++
++#define sdhc_suspend NULL
++#define sdhc_resume NULL
++
++/*-------------------------------------------------------------------------*/
++static struct of_device_id fsl_sdhc_match[] = {
++ {
++#if CONFIG_PPC_MPC5125
++ .compatible = "fsl,mpc5125-sdhc",
++#else
++ .compatible = "fsl,mpc5121-sdhc",
++#endif
++ },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, fsl_sdhc_match);
++
++static struct of_platform_driver sdhc_driver = {
++ .owner = THIS_MODULE,
++ .name = DRIVER_NAME,
++ .match_table = fsl_sdhc_match,
++ .probe = sdhc_probe,
++ .remove = __devexit_p(sdhc_remove),
++ .suspend = sdhc_suspend,
++ .resume = sdhc_resume,
++};
++
++
++/*****************************************************************************\
++ * *
++ * Driver init/exit *
++ * *
++\*****************************************************************************/
++
++static int __init sdhc_drv_init(void)
++{
++ printk(KERN_INFO DRIVER_NAME
++ ": Freescale Enhanced Secure Digital Host Controller driver\n");
++
++ return of_register_platform_driver(&sdhc_driver);
++}
++
++static void __exit sdhc_drv_exit(void)
++{
++ DBG("Exiting\n");
++ of_unregister_platform_driver(&sdhc_driver);
++}
++module_init(sdhc_drv_init);
++module_exit(sdhc_drv_exit);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("Enhanced Secure Digital Host Controller driver");
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.29/drivers/mmc/host/mpc5121_sdhc.h linux-2.6.29-v2010041601/drivers/mmc/host/mpc5121_sdhc.h
+--- linux-2.6.29/drivers/mmc/host/mpc5121_sdhc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/mmc/host/mpc5121_sdhc.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,164 @@
++/*
++ * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#ifndef __MPC5121_SDHC_H__
++#define __MPC5121_SDHC_H__
++
++/*!
++ * @file mpc5121_sdhc.h
++ *
++ * @brief Driver for the Freescale Semiconductor SDHC module.
++ *
++ * This file defines offsets and bits of SDHC registers. SDHC is also
++ * referred as MMC/SD controller
++ *
++ * @ingroup MMC_SD
++ */
++
++
++
++/* Offsets of the SDHC registers */
++#define MMC_STR_STP_CLK 0x00 /* Clock Control Reg */
++#define MMC_STATUS 0x04 /* Status Reg */
++#define MMC_CLK_RATE 0x08 /* Clock Rate Reg */
++#define MMC_CMD_DAT_CONT 0x0C /* Command and Datacont reg */
++#define MMC_RES_TO 0x10 /* Response Time-out Reg */
++#define MMC_READ_TO 0x14 /* Read Time-out Reg */
++#define MMC_BLK_LEN 0x18 /* Block Length Reg */
++#define MMC_NOB 0x1C /* Number of Blocks Reg */
++#define MMC_REV_NO 0x20 /* Revision Number Reg */
++#define MMC_INT_CNTR 0x24 /* Interrupt Control Reg */
++#define MMC_CMD 0x28 /* Command Number Reg */
++#define MMC_ARG 0x2C /* Command Argument Reg */
++#define MMC_RES_FIFO 0x34 /* Command Response Reg */
++#define MMC_BUFFER_ACCESS 0x38 /* Data Buffer Access Reg */
++
++/* Bit definitions for STR_STP_CLK */
++#define STR_STP_CLK_IPG_CLK_GATE_DIS (1<<15)
++#define STR_STP_CLK_IPG_PERCLK_GATE_DIS (1<<14)
++#define STR_STP_CLK_RESET (1<<3)
++#define STR_STP_CLK_START_CLK (1<<1)
++#define STR_STP_CLK_STOP_CLK (1<<0)
++
++/* Bit definitions for STATUS */
++#define STATUS_CARD_INSERTION (1<<31)
++#define STATUS_CARD_REMOVAL (1<<30)
++#define STATUS_YBUF_EMPTY (1<<29)
++#define STATUS_XBUF_EMPTY (1<<28)
++#define STATUS_YBUF_FULL (1<<27)
++#define STATUS_XBUF_FULL (1<<26)
++#define STATUS_BUF_UND_RUN (1<<25)
++#define STATUS_BUF_OVFL (1<<24)
++#define STATUS_SDIO_INT_ACTIVE (1<<14)
++#define STATUS_END_CMD_RESP (1<<13)
++#define STATUS_WRITE_OP_DONE (1<<12)
++#define STATUS_READ_OP_DONE (1<<11)
++#define STATUS_WR_CRC_ERROR_CODE_MASK (3<<10)
++#define STATUS_CARD_BUS_CLK_RUN (1<<8)
++#define STATUS_BUF_READ_RDY (1<<7)
++#define STATUS_BUF_WRITE_RDY (1<<6)
++#define STATUS_RESP_CRC_ERR (1<<5)
++#define STATUS_READ_CRC_ERR (1<<3)
++#define STATUS_WRITE_CRC_ERR (1<<2)
++#define STATUS_TIME_OUT_RESP (1<<1)
++#define STATUS_TIME_OUT_READ (1<<0)
++#define STATUS_ERR_MASK 0x3f
++
++/* Clock rate definitions */
++#define CLK_RATE_PRESCALER(x) ((x) & 0xF)
++#define CLK_RATE_CLK_DIVIDER(x) (((x) & 0xF) << 4)
++
++/* Bit definitions for CMD_DAT_CONT */
++#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1<<12)
++#define CMD_DAT_CONT_STOP_READWAIT (1<<11)
++#define CMD_DAT_CONT_START_READWAIT (1<<10)
++#define CMD_DAT_CONT_BUS_WIDTH_1 (0<<8)
++#define CMD_DAT_CONT_BUS_WIDTH_4 (2<<8)
++#define CMD_DAT_CONT_INIT (1<<7)
++#define CMD_DAT_CONT_WRITE (1<<4)
++#define CMD_DAT_CONT_DATA_ENABLE (1<<3)
++#define CMD_DAT_CONT_RESPONSE_FORMAT_R1 (1)
++#define CMD_DAT_CONT_RESPONSE_FORMAT_R2 (2)
++#define CMD_DAT_CONT_RESPONSE_FORMAT_R3 (3)
++#define CMD_DAT_CONT_RESPONSE_FORMAT_R4 (4)
++#define CMD_DAT_CONT_RESPONSE_FORMAT_R5 (5)
++#define CMD_DAT_CONT_RESPONSE_FORMAT_R6 (6)
++
++/* Bit definitions for INT_CNTR */
++#define INT_CNTR_SDIO_INT_WKP_EN (1<<18)
++#define INT_CNTR_CARD_INSERTION_WKP_EN (1<<17)
++#define INT_CNTR_CARD_REMOVAL_WKP_EN (1<<16)
++#define INT_CNTR_CARD_INSERTION_EN (1<<15)
++#define INT_CNTR_CARD_REMOVAL_EN (1<<14)
++#define INT_CNTR_SDIO_IRQ_EN (1<<13)
++#define INT_CNTR_DAT0_EN (1<<12)
++#define INT_CNTR_BUF_READ_EN (1<<4)
++#define INT_CNTR_BUF_WRITE_EN (1<<3)
++#define INT_CNTR_END_CMD_RES (1<<2)
++#define INT_CNTR_WRITE_OP_DONE (1<<1)
++#define INT_CNTR_READ_OP_DONE (1<<0)
++#define INT_CNTR_NO_INTR (0)
++
++#define SDHC_SLOTS_NUMBER 1
++#define READ_TO_VALUE 0x2db4
++
++struct sdhc_chip;
++
++struct sdhc_host {
++ struct fsl_dma_requestbuf *dma;
++
++ struct sdhc_chip *chip;
++ struct mmc_host *mmc; /* MMC structure */
++
++ spinlock_t lock; /* Mutex */
++
++ int flags; /* Host attributes */
++#define SDHC_USE_DMA (1<<0)
++
++ unsigned int max_clk; /* Max possible freq (MHz) */
++ unsigned int timeout_clk; /* Timeout freq (KHz) */
++
++ unsigned int clock; /* Current clock (MHz) */
++ unsigned short power; /* Current voltage */
++ unsigned short bus_width; /* current bus width */
++
++ struct mmc_request *mrq; /* Current request */
++ struct mmc_command *cmd; /* Current command */
++ struct mmc_data *data; /* Current data request */
++ int irq; /* Device IRQ */
++ unsigned long addr; /* Bus address */
++ unsigned int size; /* IO size */
++ void __iomem *ioaddr; /* Mapped address */
++
++ struct tasklet_struct card_tasklet; /* Tasklet structures */
++ struct tasklet_struct finish_tasklet;
++
++
++ struct clk *sdhc_clk;
++ unsigned int dma_size;
++ int dma_available ;
++
++ char slot_descr[20]; /* Name for reservations */
++
++
++} __attribute__ ((aligned(4)));
++
++struct sdhc_chip {
++ struct of_device *ofdev;
++
++ unsigned long quirks;
++
++ int num_slots; /* Slots on controller */
++ struct sdhc_host *hosts[0]; /* Pointers to hosts */
++};
++#endif /* __MPC5121_SDHC_H__ */
+diff -Naur linux-2.6.29/drivers/mtd/mtdpart.c linux-2.6.29-v2010041601/drivers/mtd/mtdpart.c
+--- linux-2.6.29/drivers/mtd/mtdpart.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/mtd/mtdpart.c 2010-04-13 20:23:26.000000000 +0200
+@@ -393,6 +393,8 @@
+
+ if (slave->offset == MTDPART_OFS_APPEND)
+ slave->offset = cur_offset;
++ if(slave->offset>=0xffffffff)
++ slave->offset = cur_offset;
+ if (slave->offset == MTDPART_OFS_NXTBLK) {
+ slave->offset = cur_offset;
+ if (mtd_mod_by_eb(cur_offset, master) != 0) {
+diff -Naur linux-2.6.29/drivers/mtd/nand/Kconfig linux-2.6.29-v2010041601/drivers/mtd/nand/Kconfig
+--- linux-2.6.29/drivers/mtd/nand/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/mtd/nand/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -138,6 +138,39 @@
+ help
+ This enables the NAND flash driver on the PPChameleon EVB Board.
+
++config MTD_NAND_MPC5125_NFC
++ tristate "MPC5125 built-in NAND Flash Controller support"
++ depends on PPC_MPC512x && MPC5125_TWR
++ help
++ This enables the driver for the NAND flash controller on the
++ MPC5125 SoC.
++
++config MTD_NAND_FSL
++ tristate "NAND Flash controller for MPC512x"
++ depends on PPC_MPC512x && MTD_NAND_MPC5125_NFC
++ help
++ This enables the NAND flash driver on the MPC512x SOC.
++
++config MTD_NAND_MPC5125_HARDWARE_ECC_CORRECTION
++ bool "hardware ECC support "
++ depends on MTD_NAND_FSL && MTD_NAND_MPC5125_NFC
++ help
++ This enables the support for Software ECC handling. By
++ default FSL NAND controller Hardware ECC is supported.
++
++config NFC_DMA_ENABLE
++ bool "Enable nand flash ctroller dma"
++ depends on MTD_NAND_FSL && MTD_NAND_MPC5125_NFC
++ help
++ This enables the nfc dma support
++
++#config MTD_NAND_FSL_ECC_CORRECTION_OPTION2
++# bool "ECC correction in S/W"
++# depends on MTD_NAND_FSL && MTD_NAND_MPC5125_NFC
++# help
++# This enables the Option2 NFC ECC correction in software. By
++# default Option 1 is selected. Enable if you need option2 ECC correction.
++
+ config MTD_NAND_S3C2410
+ tristate "NAND Flash support for S3C2410/S3C2440 SoC"
+ depends on ARCH_S3C2410
+diff -Naur linux-2.6.29/drivers/mtd/nand/Makefile linux-2.6.29-v2010041601/drivers/mtd/nand/Makefile
+--- linux-2.6.29/drivers/mtd/nand/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/mtd/nand/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -13,6 +13,7 @@
+ obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
+ obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
+ obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
++obj-$(CONFIG_MTD_NAND_MPC5125_NFC) += mpc5125_nfc.o
+ obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
+ obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
+ obj-$(CONFIG_MTD_NAND_H1900) += h1910.o
+diff -Naur linux-2.6.29/drivers/mtd/nand/mpc5125_nfc.c linux-2.6.29-v2010041601/drivers/mtd/nand/mpc5125_nfc.c
+--- linux-2.6.29/drivers/mtd/nand/mpc5125_nfc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/mtd/nand/mpc5125_nfc.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,1295 @@
++/*
++ * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * Author: Shaohui Xie <b21989@freescale.com>
++ *
++ * Description:
++ * MPC5125 Nand driver.
++ *
++ * Based on original driver mpc5121_nfc.c.
++ *
++ * This 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.
++ */
++ /*
++ modyfied by Cloudy Chen <chen_yunsong@mtcera.com>
++ */
++
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of_device.h>
++#include <linux/of_platform.h>
++
++#include <asm/mpc512x.h>
++#include <asm/mpc5125_nfc.h>
++#include <linux/dma-mapping.h>
++
++#define DRV_NAME "mpc5125_nfc"
++#define DRV_VERSION "0.5"
++#define SPARE_BUFFER_MAX_SIZE 0x400
++#define DATA_BUFFER_MAX_SIZE 0x2000
++/* Timeouts */
++#define NFC_RESET_TIMEOUT 1000 /* 1 ms */
++#define NFC_TIMEOUT (HZ / 10) /* 1/10 s */
++
++#ifdef CONFIG_NFC_DMA_ENABLE
++#define NFC_DMA_ENABLE 1
++#else
++#define NFC_DMA_ENABLE 0
++#endif
++struct mpc5125_nfc_prv {
++ struct mtd_info mtd;
++ struct device *dev;
++ struct nand_chip chip;
++#ifdef CONFIG_MTD_PARTITIONS
++ struct mtd_partition *parts;
++ int nr_parts;
++#endif
++ int irq;
++ void __iomem *regs;
++ struct clk *clk;
++ wait_queue_head_t irq_waitq;
++ uint column;
++ int spareonly;
++ u32 irq_stat;
++ u32 wait_timeout;
++ void __iomem *csreg;
++ void *data_buffers;
++ dma_addr_t data_buffers_phyaddr;
++ void *ops_buffer;
++ dma_addr_t ops_buffer_phyaddr;
++ void *tmp_buf;
++ struct semaphore int_sem;
++ unsigned int sync_flags;
++};
++
++static int get_status;
++static int get_id;
++
++#define NFC_IRQ_ENABLE (IDLE_EN_MASK|WERR_EN_MASK)
++#define NFC_IRQ_MASK (IDLE_IRQ_MASK|WERR_IRQ_MASK)
++
++#ifdef CONFIG_MTD_NAND_MPC5125_HARDWARE_ECC_CORRECTION
++static int hardware_ecc = 1;
++#else
++static int hardware_ecc = 0;
++#endif
++#define MPC5125_NFC_ECC_STATUS_ADD (NFC_SPARE_AREA(0)+0xf0)
++#if 1
++/*for ecc_MODE=0x6 45bytes*2*/
++static struct nand_ecclayout nand_hw_eccoob_4k = {
++ .eccbytes = 90, /* actually 72 but only room for 64 */
++ .eccpos = {
++ /* 9 bytes of ecc for each 512 bytes of data */
++ 19,20,21,22,23,24,25,26,27,28,29,30,
++ 31,32,33,34,35,36,37,38,39,40,
++ 41, 42, 43, 44, 45, 46, 47,48,49,50,
++ 51,52,53,54,55, 56, 57, 58, 59, 60,
++ 61, 62, 63,
++ 83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,
++ 98,99,100,
++ 101,102,103,104,105,106,107,108,109,110,
++ 111,112,113,114,115,116,117,118,119,120,
++ 121,122,123,124,125,126,127/* 120, 121, 122, 123, 124, 125, 126, 127, */
++ },
++ .oobavail = 30,
++ .oobfree = { {4, 15}, {68, 15}}
++};
++#else
++/*for ecc_MODE=0x5 30bytes*2*/
++static struct nand_ecclayout nand_hw_eccoob_4k = {
++ .eccbytes = 60, /* actually 72 but only room for 64 */
++ .eccpos = {
++ /* 9 bytes of ecc for each 512 bytes of data */
++ 34,35,36,37,38,39,40,
++ 41, 42, 43, 44, 45, 46, 47,48,49,50,
++ 51,52,53,54,55, 56, 57, 58, 59, 60,
++ 61, 62, 63,
++ 98,99,100,
++ 101,102,103,104,105,106,107,108,109,110,
++ 111,112,113,114,115,116,117,118,119,120,
++ 121,122,123,124,125,126,127/* 120, 121, 122, 123, 124, 125, 126, 127, */
++ },
++ .oobavail = 48,
++ .oobfree = { {8, 24}, {68, 24}}
++};
++#endif
++
++#if NFC_DMA_ENABLE
++static void mpc5125_dma_config(struct mtd_info *mtd, struct nand_chip *chip,unsigned isRead);
++static void mpc5125_nand_dma_wait(struct mtd_info *mtd, struct nand_chip *chip);
++#endif
++
++static struct nand_ecclayout nand_hw_eccoob_4k_218_spare = {
++ .eccbytes = 64, /* actually 144 but only room for 64 */
++ .eccpos = {
++ /* 18 bytes of ecc for each 512 bytes of data */
++ 7, 8, 9, 10, 11, 12, 13, 14, 15,
++ 16, 17, 18, 19, 20, 21, 22, 23, 24,
++ 33, 34, 35, 36, 37, 38, 39, 40, 41,
++ 42, 43, 44, 45, 46, 47, 48, 49, 50,
++ 59, 60, 61, 62, 63, 64, 65, 66, 67,
++ 68, 69, 70, 71, 72, 73, 74, 75, 76,
++ 85, 86, 87, 88, 89, 90, 91, 92, 93,
++ 94, /* 95, 96, 97, 98, 99, 100, 101, 102,
++ 111, 112, 113, 114, 115, 116, 117, 118, 119,
++ 120, 121, 122, 123, 124, 125, 126, 127, 128,
++ 137, 138, 139, 140, 141, 142, 143, 144, 145,
++ 146, 147, 148, 149, 150, 151, 152, 153, 154,
++ 163, 164, 165, 166, 167, 168, 169, 170, 171,
++ 172, 173, 174, 175, 176, 177, 178, 179, 180,
++ 189, 190, 191, 192, 193, 194, 195, 196, 197,
++ 198, 199, 200, 201, 202, 203, 204, 205, 206, */
++ },
++ .oobavail = 4,
++ .oobfree = {{0, 5}, {26, 8}, {52, 8}, {78, 8},
++ {104, 8}, {130, 8}, {156, 8}, {182, 8}}
++};
++
++#ifdef CONFIG_MTD_PARTITIONS
++static const char *mpc5125_nfc_pprobes[] = { "cmdlinepart", NULL };
++#endif
++
++static inline u32 nfc_read(struct mtd_info *mtd, uint reg)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++
++ return in_be32(prv->regs + reg);
++}
++
++/* Write NFC register */
++static inline void nfc_write(struct mtd_info *mtd, uint reg, u32 val)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ out_be32(prv->regs + reg, val);
++}
++
++/* Set bits in NFC register */
++static inline void nfc_set(struct mtd_info *mtd, uint reg, u32 bits)
++{
++ nfc_write(mtd, reg, nfc_read(mtd, reg) | bits);
++}
++
++/* Clear bits in NFC register */
++static inline void nfc_clear(struct mtd_info *mtd, uint reg, u32 bits)
++{
++ nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits);
++}
++
++
++static inline void
++nfc_set_field(struct mtd_info *mtd, u32 reg, u32 mask, u32 shift, u32 val)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++
++ out_be32(prv->regs + reg,
++ (in_be32(prv->regs + reg) & (~mask))
++ | val << shift);
++}
++
++static inline int
++nfc_get_field(struct mtd_info *mtd, u32 reg, u32 field_mask)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++
++ return in_be32(prv->regs + reg) & field_mask;
++}
++
++static inline u8 nfc_check_status(struct mtd_info *mtd)
++{
++ u8 fls_status = 0;
++ fls_status = nfc_get_field(mtd, NFC_FLASH_STATUS2, STATUS_BYTE1_MASK);
++ return fls_status;
++}
++
++/* clear cmd_done and cmd_idle falg for the coming command */
++static void mpc5125_nfc_clear(struct mtd_info *mtd)
++{
++ nfc_write(mtd, NFC_IRQ_STATUS, 1 << CMD_DONE_CLEAR_SHIFT);
++ nfc_write(mtd, NFC_IRQ_STATUS, 1 << IDLE_CLEAR_SHIFT);
++ nfc_write(mtd, NFC_IRQ_STATUS, 1 << WERR_CLEAR_SHIFT);
++}
++
++/* Wait for operation complete */
++static void mpc5125_nfc_done(struct mtd_info *mtd)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ int rv;
++ unsigned int wait_time=NFC_TIMEOUT;
++ mpc5125_nfc_clear(mtd);
++ nfc_set(mtd, NFC_IRQ_STATUS, NFC_IRQ_ENABLE);
++ prv->wait_timeout=0;
++ prv->sync_flags=0;
++ nfc_set_field(mtd, NFC_FLASH_CMD2, START_MASK,
++ START_SHIFT, 1);
++ {
++ if (!(nfc_read(mtd,NFC_IRQ_STATUS)&(NFC_IRQ_MASK))){
++ rv = wait_event_timeout(prv->irq_waitq,
++ (nfc_read(mtd,NFC_IRQ_STATUS)&NFC_IRQ_MASK),
++ wait_time);
++ if ((!rv))
++ {
++ prv->irq_stat=nfc_read(mtd,NFC_IRQ_STATUS);
++
++ if(!(prv->sync_flags))
++ printk(KERN_WARNING DRV_NAME
++ ":Lost irq :%08x.\n");
++
++ printk(KERN_WARNING DRV_NAME
++ ": Timeout while waiting for BUSY :%08x.\n",prv->irq_stat);
++ prv->wait_timeout=1;
++
++ }
++ }
++ }
++ mpc5125_nfc_clear(mtd);
++}
++
++static inline u8 mpc5125_nfc_get_id(struct mtd_info *mtd, int col)
++{
++ u32 flash_id1 = 0;
++ u8 *pid;
++
++ flash_id1 = nfc_read(mtd, NFC_FLASH_STATUS1);
++ pid = (u8 *)&flash_id1;
++
++ return *(pid + col);
++}
++
++static inline u8 mpc5125_nfc_get_status(struct mtd_info *mtd)
++{
++ u32 flash_status = 0;
++ u8 *pstatus;
++
++ flash_status = nfc_read(mtd, NFC_FLASH_STATUS2);
++ pstatus = (u8 *)&flash_status;
++
++ return *(pstatus + 3);
++}
++
++/* Invoke command cycle */
++static inline void
++mpc5125_nfc_send_cmd(struct mtd_info *mtd, u32 cmd_byte1,
++ u32 cmd_byte2, u32 cmd_code)
++{
++ mpc5125_nfc_clear(mtd);
++ nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_BYTE1_MASK,
++ CMD_BYTE1_SHIFT, cmd_byte1);
++
++ nfc_set_field(mtd, NFC_FLASH_CMD1, CMD_BYTE2_MASK,
++ CMD_BYTE2_SHIFT, cmd_byte2);
++
++ nfc_set_field(mtd, NFC_FLASH_CMD2, BUFNO_MASK,
++ BUFNO_SHIFT, 0);
++
++ nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_CODE_MASK,
++ CMD_CODE_SHIFT, cmd_code);
++
++ if (cmd_code == RANDOM_OUT_CMD_CODE)
++ nfc_set_field(mtd, NFC_FLASH_CMD2, BUFNO_MASK,
++ BUFNO_SHIFT, 1);
++}
++
++/* Receive ID and status from NAND flash */
++static inline void
++mpc5125_nfc_send_one_byte(struct mtd_info *mtd, u32 cmd_byte1, u32 cmd_code)
++{
++ mpc5125_nfc_clear(mtd);
++ nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_BYTE1_MASK,
++ CMD_BYTE1_SHIFT, cmd_byte1);
++
++ nfc_set_field(mtd, NFC_FLASH_CMD2, BUFNO_MASK,
++ BUFNO_SHIFT, 0);
++
++ nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_CODE_MASK,
++ CMD_CODE_SHIFT, cmd_code);
++}
++
++/* NFC interrupt handler */
++static irqreturn_t mpc5125_nfc_irq(int irq, void *data)
++{
++ struct mtd_info *mtd = data;
++ struct nand_chip *chip = mtd->priv;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ prv->irq_stat=nfc_read(mtd,NFC_IRQ_STATUS);
++ nfc_clear(mtd, NFC_IRQ_STATUS, NFC_IRQ_ENABLE);
++ wake_up(&prv->irq_waitq);
++ /*mpc5125_nfc_clear(mtd);*/
++ prv->sync_flags|=1;
++ return IRQ_HANDLED;
++}
++
++/* Do address cycle(s) */
++static void mpc5125_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
++{
++
++ if (column != -1) {
++ nfc_set_field(mtd, NFC_COL_ADDR,
++ COL_ADDR_MASK,
++ COL_ADDR_SHIFT, column);
++ }
++
++ if (page != -1) {
++ nfc_set_field(mtd, NFC_ROW_ADDR,
++ ROW_ADDR_MASK,
++ ROW_ADDR_SHIFT, page);
++ }
++ /* DMA Disable */
++#if (NFC_DMA_ENABLE<1)
++ nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_MASK);
++#endif
++ /* PAGE_CNT = 1 */
++ nfc_set_field(mtd, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK,
++ CONFIG_PAGE_CNT_SHIFT, 0x2);
++}
++
++
++/* Control chips select signal on ADS5125 board */
++static void ads5125_select_chip(struct mtd_info *mtd, int chip)
++{
++
++ if ((chip < 0)||(chip>3)) {
++ nfc_set_field(mtd, NFC_ROW_ADDR,
++ ROW_ADDR_CHIP_SEL_RB_MASK,
++ ROW_ADDR_CHIP_SEL_RB_SHIFT, 0);
++
++ nfc_set_field(mtd, NFC_ROW_ADDR,
++ ROW_ADDR_CHIP_SEL_MASK,
++ ROW_ADDR_CHIP_SEL_SHIFT, 0);
++ return;
++ }
++
++ nfc_set_field(mtd, NFC_ROW_ADDR,
++ ROW_ADDR_CHIP_SEL_RB_MASK,
++ ROW_ADDR_CHIP_SEL_RB_SHIFT, (1<<chip));
++
++ nfc_set_field(mtd, NFC_ROW_ADDR,
++ ROW_ADDR_CHIP_SEL_MASK,
++ ROW_ADDR_CHIP_SEL_SHIFT, (1<<chip));
++
++}
++
++/* Read NAND Ready/Busy signal */
++static int mpc5125_nfc_dev_ready(struct mtd_info *mtd)
++{
++ /*
++ * NFC handles ready/busy signal internally. Therefore, this function
++ * always returns status as ready.
++ */
++ return 1;
++}
++
++/* Write command to NAND flash */
++static void mpc5125_nfc_command(struct mtd_info *mtd, unsigned command,
++ int column, int page)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++
++ prv->column = (column >= 0) ? column : 0;
++ prv->spareonly = 0;
++ get_id = 0;
++ get_status = 0;
++
++
++ switch (command) {
++ case NAND_CMD_PAGEPROG:
++ mpc5125_nfc_send_cmd(mtd,
++ PROGRAM_PAGE_CMD_BYTE1,
++ PROGRAM_PAGE_CMD_BYTE2,
++#if (NFC_DMA_ENABLE)
++ DMA_PROGRAM_PAGE_CMD_CODE);
++ /*
++ nfc_set_field(mtd, NFC_FLASH_CMD2, CMD_BYTE1_MASK,
++ CMD_BYTE1_SHIFT, READ_STATUS_CMD_BYTE);
++ */
++ mpc5125_dma_config(mtd,chip,0);
++#else
++ PROGRAM_PAGE_CMD_CODE);
++#endif
++ break;
++ /*
++ * NFC does not support sub-page reads and writes,
++ * so emulate them using full page transfers.
++ */
++ case NAND_CMD_READ0:
++ column = 0;
++ goto read0;
++ break;
++
++ case NAND_CMD_READ1:
++ prv->column += 256;
++ command = NAND_CMD_READ0;
++ column = 0;
++ goto read0;
++ break;
++
++ case NAND_CMD_READOOB:
++ prv->spareonly = 1;
++ command = NAND_CMD_READ0;
++ column = 0;
++read0:
++
++ mpc5125_nfc_send_cmd(mtd,
++ PAGE_READ_CMD_BYTE1,
++ PAGE_READ_CMD_BYTE2,
++ READ_PAGE_CMD_CODE);
++#if NFC_DMA_ENABLE
++ mpc5125_dma_config( mtd, chip,1);
++#endif
++ break;
++
++ case NAND_CMD_SEQIN:
++ mpc5125_nfc_command(mtd, NAND_CMD_READ0, column, page);
++ column = 0;
++ break;
++
++ case NAND_CMD_ERASE1:
++ mpc5125_nfc_send_cmd(mtd,
++ ERASE_CMD_BYTE1,
++ ERASE_CMD_BYTE2,
++ ERASE_CMD_CODE);
++ break;
++ case NAND_CMD_ERASE2:
++ return;
++ case NAND_CMD_READID:
++ get_id = 1;
++ mpc5125_nfc_send_one_byte(mtd, command, READ_ID_CMD_CODE);
++ break;
++ case NAND_CMD_STATUS:
++ get_status = 1;
++ mpc5125_nfc_send_one_byte(mtd, command, STATUS_READ_CMD_CODE);
++ break;
++ case NAND_CMD_RNDOUT:
++ mpc5125_nfc_send_cmd(mtd,
++ RANDOM_OUT_CMD_BYTE1,
++ RANDOM_OUT_CMD_BYTE2,
++ RANDOM_OUT_CMD_CODE);
++ break;
++ default:
++ return;
++ }
++
++ mpc5125_nfc_addr_cycle(mtd, column, page);
++ mpc5125_nfc_done(mtd);
++
++#if (NFC_DMA_ENABLE)
++ /*mpc5125_nand_dma_wait(mtd,chip);*/
++ nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_MASK);
++#endif
++
++
++}
++
++/* Copy data from/to NFC spare buffers. */
++static void mpc5125_nfc_copy_spare(struct mtd_info *mtd, uint offset,
++ u8 *buffer, uint size, int wr)
++{
++ struct nand_chip *nand = mtd->priv;
++ struct mpc5125_nfc_prv *prv = nand->priv;
++ u16 ooblen = mtd->oobsize;
++ u8 i, count;
++ uint sbsize, blksize;
++
++ /*
++ * NAND spare area is available through NFC spare buffers.
++ * The NFC divides spare area into (page_size / 512) chunks.
++ * Each chunk is placed into separate spare memory area, using
++ * first (spare_size / num_of_chunks) bytes of the buffer.
++ *
++ * For NAND device in which the spare area is not divided fully
++ * by the number of chunks, number of used bytes in each spare
++ * buffer is rounded down to the nearest even number of bytes,
++ * and all remaining bytes are added to the last used spare area.
++ *
++ * For more information read section 26.6.10 of MPC5121e
++ * Microcontroller Reference Manual, Rev. 3.
++ */
++
++ /* Calculate number of valid bytes in each spare buffer */
++ count = mtd->writesize >> 11;
++ count=(count>0)?count:1;
++ sbsize = (ooblen / count >> 1) << 1;
++ /*printk("%s line:%d %s len:%d\n",__FUNCTION__,__LINE__,wr?"write":"read",size);*/
++ for(i=0;(i<count)&&size;i++)
++ {
++ blksize = min(sbsize, size);
++ if(wr)
++ {
++ memcpy_toio(prv->regs + NFC_SPARE_AREA(i) ,
++ buffer, blksize);
++ }
++ else
++ {
++ memcpy_fromio(buffer,
++ prv->regs + NFC_SPARE_AREA(i), blksize);
++ }
++ /*mpc5125_spare_debug(buffer,blksize);*/
++ buffer += blksize;
++ offset += blksize;
++ size -= blksize;
++ }
++}
++
++/* Copy data from/to NFC main and spare buffers */
++static void mpc5125_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len,
++ int wr)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ uint c = prv->column;
++ uint l;
++ /* Handle spare area access */
++ if (prv->spareonly || c >= mtd->writesize) {
++ /* Calculate offset from beginning of spare area */
++ if (c >= mtd->writesize)
++ c -= mtd->writesize;
++
++ prv->column += len;
++#if NFC_DMA_ENABLE
++ if(wr)
++ {
++ memcpy(prv->ops_buffer,buf,len);
++ }
++ else
++ {
++ memcpy(buf,prv->ops_buffer,len);
++ }
++#else
++ mpc5125_nfc_copy_spare(mtd, c, buf, len, wr);
++#endif
++ return;
++ }
++
++ /*
++ * Handle main area access - limit copy length to prevent
++ * crossing main/spare boundary.
++ */
++ l = min((uint)len, mtd->writesize - c);
++ /*
++ printk("%s line:%d %s l=0x%x,mtd->writesize=0x%x,c=0x%x \n",__FUNCTION__,__LINE__,wr?"write":"read",l,mtd->writesize,c);
++ */
++ prv->column += l;
++
++ if (wr)
++ {
++ unsigned int size,i;
++#if NFC_DMA_ENABLE
++ memcpy(prv->data_buffers+c,buf,len);
++#else
++ for(i=(c/PAGE_2K);i<4;i++)
++ {
++ size=min(len,PAGE_2K);
++ memcpy_toio(prv->regs + NFC_MAIN_AREA(i) + c, buf, size);
++ buf+=size;
++ len-=size;
++ if(!len)break;
++ }
++#endif
++ }
++ else {
++ if (get_status) {
++ get_status = 0;
++ *buf = mpc5125_nfc_get_status(mtd);
++ } else if (l == 1 && c <= 3 && get_id) {
++ *buf = mpc5125_nfc_get_id(mtd, c);
++ } else
++ {
++ unsigned int size,i;
++#if NFC_DMA_ENABLE
++ if(len==mtd->writesize)
++ {
++ memcpy(buf,prv->data_buffers+c,len);
++ }
++ else
++#endif
++ for(i=(c/PAGE_2K);i<4;i++)
++ {
++ size=min(len,PAGE_2K);
++ memcpy_fromio(buf,prv->regs + NFC_MAIN_AREA(i) + c, size);
++ buf+=size;
++ len-=size;
++ if(!len)break;
++ }
++ }
++ }
++}
++
++/* Read data from NFC buffers */
++static void mpc5125_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++ mpc5125_nfc_buf_copy(mtd, buf, len, 0);
++}
++
++/* Write data to NFC buffers */
++static void mpc5125_nfc_write_buf(struct mtd_info *mtd,
++ const u_char *buf, int len)
++{
++ mpc5125_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
++}
++
++/* Compare buffer with NAND flash */
++static int mpc5125_nfc_verify_buf(struct mtd_info *mtd,
++ const u_char *buf, int len)
++{
++ u_char tmp[256];
++ uint bsize;
++ while (len) {
++ bsize = min(len, 256);
++ mpc5125_nfc_read_buf(mtd, tmp, bsize);
++ if (memcmp(buf, tmp, bsize))
++ return 1;
++ buf += bsize;
++ len -= bsize;
++ }
++ return 0;
++}
++
++/* Read byte from NFC buffers */
++static u8 mpc5125_nfc_read_byte(struct mtd_info *mtd)
++{
++ u8 tmp;
++ mpc5125_nfc_read_buf(mtd, &tmp, sizeof(tmp));
++ return tmp;
++}
++
++/* Read word from NFC buffers */
++static u16 mpc5125_nfc_read_word(struct mtd_info *mtd)
++{
++ u16 tmp;
++ mpc5125_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
++ return tmp;
++}
++
++/*
++ * Read NFC configuration from Reset Config Word
++ *
++ */
++static int mpc5125_nfc_read_hw_config(struct mtd_info *mtd)
++{
++ uint rcw_pagesize = 0;
++ uint rcw_sparesize = 0;
++
++ rcw_pagesize = 4096;
++ rcw_sparesize = 128;
++ mtd->writesize = rcw_pagesize;
++ mtd->oobsize = rcw_sparesize;
++ return 0;
++}
++
++/* Free driver resources */
++static void mpc5125_nfc_free(struct device *dev, struct mtd_info *mtd)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++
++ if (prv->clk) {
++ clk_disable(prv->clk);
++ clk_put(prv->clk);
++ }
++ if (prv->csreg)
++ iounmap(prv->csreg);
++}
++
++#ifdef CONFIG_MTD_PARTITIONS
++static int parse_flash_partitions(struct mtd_info *mtd,struct device_node *dp)
++{
++ int i;
++ const char *name;
++ struct device_node *pp;
++ struct nand_chip *chip = mtd->priv;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ int nr_parts = 0;
++
++ for (pp = dp->child; pp; pp = pp->sibling)
++ nr_parts++;
++
++ if (!nr_parts)
++ return 0;
++
++ prv->parts = devm_kzalloc(prv->dev,
++ nr_parts * sizeof(struct mtd_partition),
++ GFP_KERNEL);
++ if (!prv->parts)
++ return -ENOMEM;
++ for (pp = dp->child, i =0; pp; pp = pp->sibling, i++) {
++ const u32 *reg;
++ int len;
++
++ reg = of_get_property(pp, "reg", &len);
++ if (!reg || (len != 2*sizeof(u32))) {
++ printk(KERN_ERR DRV_NAME ": "
++ "Invalid 'reg' on %s\n", dp->full_name);
++ kfree(prv->parts);
++ prv->parts = NULL;
++ return -EINVAL;
++ }
++ prv->parts[i].offset = reg[0];
++ prv->parts[i].size = reg[1];
++
++ name = of_get_property(pp, "label", &len);
++ if (!name)
++ name = of_get_property(pp, "name", &len);
++ prv->parts[i].name = (char *)name;
++
++ if (of_get_property(pp, "read-only", &len))
++ prv->parts[i].mask_flags = MTD_WRITEABLE;
++ }
++ return nr_parts;
++}
++#endif
++static void mpc5125_nand_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_ECC_MODE_MASK,
++ CONFIG_ECC_MODE_SHIFT, ECC_30_BYTE);
++ return;
++}
++/*
++ * Function to correct the detected errors. This NFC corrects all the errors
++ * detected. So this function is not required.
++ */
++static int mpc5125_nand_correct_data(struct mtd_info *mtd, u_char * dat,
++ u_char * read_ecc, u_char * calc_ecc)
++{
++ panic("Shouldn't be called here: %d\n", __LINE__);
++ return 0; /* FIXME */
++}
++
++/*
++ * Function to calculate the ECC for the data to be stored in the Nand device.
++ * This NFC has a hardware RS(511,503) ECC engine together with the RS ECC
++ * CONTROL blocks are responsible for detection and correction of up to
++ * 4 symbols of 9 bits each in 528 byte page.
++ * So this function is not required.
++ */
++
++static int mpc5125_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat,
++ u_char * ecc_code)
++{
++ panic(KERN_ERR "Shouldn't be called here %d \n", __LINE__);
++ return 0; /* FIXME */
++}
++static int mpc5125_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++ int page, int sndcmd)
++{
++
++ if(sndcmd)
++ {
++ mpc5125_nfc_command(mtd,NAND_CMD_READ0,0,page);
++ sndcmd=0;
++ }
++#if NFC_DMA_ENABLE
++{
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ memcpy(chip->oob_poi,prv->ops_buffer, mtd->oobsize);
++}
++#else
++ mpc5125_nfc_copy_spare(mtd,0,chip->oob_poi, mtd->oobsize,0);
++#endif
++ return sndcmd;
++}
++
++static int mpc5125_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
++ int page)
++{
++
++ unsigned int stat;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ mpc5125_nfc_command(mtd,NAND_CMD_READ0,0,page);
++#if NFC_DMA_ENABLE
++ memcpy(prv->ops_buffer,chip->oob_poi, mtd->oobsize);
++#else
++ mpc5125_nfc_copy_spare(mtd,0,chip->oob_poi, mtd->oobsize,1);
++#endif
++ mpc5125_nfc_command(mtd,NAND_CMD_PAGEPROG,0,page);
++ if(prv->wait_timeout)
++ {
++ printk(KERN_ERR"%s line:%d wait timeout.\n",__FUNCTION__,__LINE__);
++ return -EIO;
++ }
++ if(prv->irq_stat&WERR_IRQ_MASK)
++ {
++ printk(KERN_ERR"%s line:%d faield.\n",__FUNCTION__,__LINE__);
++ return -EIO;
++ }
++ return 0;
++}
++
++static int mpc5125_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
++ uint8_t * buf)
++{
++ unsigned int stat;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ u8 *erase_page_check,ecc_bytes=0,i;
++ u8 ecc_bytes_map[]={0,8,12,15,23,30,45,60};
++ stat=nfc_read(mtd, NFC_FLASH_CONFIG);
++ stat>>=17;
++ stat&=0x7;
++ ecc_bytes=ecc_bytes_map[stat];
++ erase_page_check=(u8 *)(PAGE_virtual_2K-ecc_bytes+prv->regs);
++ stat=nfc_read(mtd, MPC5125_NFC_ECC_STATUS_ADD+4);
++ DEBUG(MTD_DEBUEVEL3,"%s line:%d stat:%08x\n",__FUNCTION__,__LINE__,stat);
++ if(stat&0x80)
++ {
++ /*check the page is erased*/
++ if(stat&0x3f)
++ {
++ mtd->ecc_stats.failed++;
++ printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
++ }
++
++ }
++ else if(stat&0x3f)
++ {
++ /*printk(KERN_WARNING "Correctable ECC %d\n",stat&0x3f);*/
++ mtd->ecc_stats.corrected+=stat&0x3f;
++ }
++#if NFC_DMA_ENABLE
++ memcpy(buf,prv->data_buffers,mtd->writesize);
++ memcpy(chip->oob_poi,prv->ops_buffer, mtd->oobsize);
++#else
++ mpc5125_nfc_buf_copy(mtd, buf, mtd->writesize, 0);
++ mpc5125_nfc_copy_spare(mtd,0,chip->oob_poi, mtd->oobsize,0);
++#endif
++ return 0;
++}
++
++static void mpc5125_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t * buf)
++{
++#if NFC_DMA_ENABLE
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ memcpy(prv->data_buffers,buf,mtd->writesize);
++ memcpy(prv->ops_buffer,chip->oob_poi, mtd->oobsize);
++#else
++ mpc5125_nfc_buf_copy(mtd, buf, mtd->writesize, 1);
++ mpc5125_nfc_copy_spare(mtd,0,chip->oob_poi, mtd->oobsize,1);
++#endif
++
++}
++static int chip_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf, int page, int cached, int raw)
++{
++ int status;
++#if (NFC_DMA_ENABLE<1)
++ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
++#endif
++ if (unlikely(raw))
++ chip->ecc.write_page_raw(mtd, chip, buf);
++ else
++ chip->ecc.write_page(mtd, chip, buf);
++
++ /*
++ * Cached progamming disabled for now, Not sure if its worth the
++ * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
++ */
++ cached = 0;
++
++ if (!cached || !(chip->options & NAND_CACHEPRG)) {
++#if NFC_DMA_ENABLE
++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, 0x00, page);
++#else
++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++#endif
++
++ status = chip->waitfunc(mtd, chip);
++ /*
++ * See if operation failed and additional status checks are
++ * available
++ */
++ if ((status & NAND_STATUS_FAIL) && (chip->errstat))
++ status = chip->errstat(mtd, chip, FL_WRITING, status,
++ page);
++
++ if (status & NAND_STATUS_FAIL)
++ return -EIO;
++ } else {
++#if NFC_DMA_ENABLE
++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, 0x00, page);
++#else
++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++#endif
++ status = chip->waitfunc(mtd, chip);
++ }
++ if(nfc_get_field(mtd, NFC_IRQ_STATUS,WERR_IRQ_MASK|WERR_STATUS_MASK))
++ {
++ printk(KERN_ERR"%s line:%d write page %d failed\n",__FUNCTION__,__LINE__,page);
++ nfc_set_field(mtd, NFC_IRQ_STATUS,
++ WERR_CLEAR_MASK,
++ WERR_CLEAR_SHIFT, 1);
++ return -EIO;
++ }
++ return 0;
++}
++#if NFC_DMA_ENABLE
++static void mpc5125_dma_config(struct mtd_info *mtd, struct nand_chip *chip,unsigned isRead)
++{
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ nfc_write(mtd, NFC_DMA1_ADDR,prv->data_buffers_phyaddr);
++ nfc_write(mtd, NFC_DMA2_ADDR,prv->ops_buffer_phyaddr);
++ if(isRead)
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_DMA_REQ_MASK,
++ CONFIG_DMA_REQ_SHIFT, 1);
++ else
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_DMA_REQ_MASK,
++ CONFIG_DMA_REQ_SHIFT, 0);
++ nfc_set_field(mtd, NFC_FLASH_COMMAND_REPEAT,
++ COMMAND_REPEAT_MASK,
++ COMMAND_REPEAT_SHIFT, 0);
++ nfc_set_field(mtd, NFC_FLASH_CMD2, BUFNO_MASK,
++ BUFNO_SHIFT, 0);
++}
++static void mpc5125_nand_dma_wait(struct mtd_info *mtd, struct nand_chip *chip)
++{
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ if(((DMA_BUSY_MASK|ECC_BUSY_MASK|RESIDUE_BUSY_MASK)&nfc_read(mtd,NFC_IRQ_STATUS)))
++ {
++ int rv;
++ rv=wait_event_timeout(prv->irq_waitq,
++ (nfc_read(mtd,NFC_IRQ_STATUS)&(CMD_DONE_IRQ_MASK|IDLE_IRQ_MASK))==(CMD_DONE_IRQ_MASK|IDLE_IRQ_MASK), NFC_TIMEOUT*4);
++ if (!rv)
++ {
++
++ prv->irq_stat=nfc_read(mtd,NFC_IRQ_STATUS);
++ printk(KERN_ERR DRV_NAME"%s timeour status:%08x\n",__FUNCTION__,prv->irq_stat);
++ prv->wait_timeout=1;
++
++ }
++ }
++}
++/**
++ * nand_read_page_raw - [Intern] read raw page data without ecc
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: buffer to store read data
++ */
++static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++ uint8_t *buf)
++{
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ memcpy(buf,prv->data_buffers,mtd->writesize);
++ memcpy(chip->oob_poi,prv->ops_buffer, mtd->oobsize);
++ return 0;
++}
++/**
++ * nand_write_page_raw - [Intern] raw page write function
++ * @mtd: mtd info structure
++ * @chip: nand chip info structure
++ * @buf: data buffer
++ */
++static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf)
++{
++ struct mpc5125_nfc_prv *prv = chip->priv;
++ memcpy(prv->data_buffers,buf,mtd->writesize);
++ memcpy(prv->ops_buffer,chip->oob_poi, mtd->oobsize);
++ mpc5125_dma_config(mtd,chip,0);
++}
++#endif
++
++static int __init mpc5125_nfc_probe(struct of_device *op,
++ const struct of_device_id *match)
++{
++ struct device_node *rootnode, *dn = op->node;
++ struct device *dev = &op->dev;
++ struct mpc5125_nfc_prv *prv;
++ struct resource res;
++ struct mtd_info *mtd;
++ struct nand_chip *chip;
++ unsigned long regs_paddr, regs_size;
++ const uint *chips_no;
++ int retval = 0;
++ int len;
++ prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
++ if (!prv) {
++ printk(KERN_ERR DRV_NAME ": Memory exhausted!\n");
++ return -ENOMEM;
++ }
++ mtd = &prv->mtd;
++ chip = &prv->chip;
++
++ mtd->priv = chip;
++ chip->priv = prv;
++ prv->dev = dev;
++
++ /* Read NFC configuration from Reset Config Word */
++ retval = mpc5125_nfc_read_hw_config(mtd);
++ if (retval) {
++ printk(KERN_ERR DRV_NAME ": Unable to read NFC config!\n");
++ return retval;
++ }
++ /*speed up nand flash r/w add by cloudy*/
++ {
++ volatile u32 *nfc_div=ioremap(0x80000f80,sizeof(u32));
++ if(!nfc_div)
++ {
++ printk(KERN_ERR DRV_NAME ": Unable to speed up nfc !\n");
++ }
++ else
++ {
++#ifdef CONFIG_MTD_NAND_MPC5125_HARDWARE_ECC_CORRECTION
++ *nfc_div=(0x1430<<16);
++#else
++ *nfc_div=(0x2860<<16);
++#endif
++ iounmap(nfc_div);
++ }
++ }
++ prv->irq = irq_of_parse_and_map(dn, 0);
++ if (prv->irq == NO_IRQ) {
++ printk(KERN_ERR DRV_NAME ": Error mapping IRQ!\n");
++ return -EINVAL;
++ }
++ retval = of_address_to_resource(dn, 0, &res);
++ if (retval) {
++ printk(KERN_ERR DRV_NAME ": Error parsing memory region!\n");
++ return retval;
++ }
++ chips_no = of_get_property(dn, "chips", &len);
++ if (!chips_no || len != sizeof(*chips_no)) {
++ printk(KERN_ERR DRV_NAME ": Invalid/missing 'chips' "
++ "property!\n");
++ return -EINVAL;
++ }
++ regs_paddr = res.start;
++ regs_size = res.end - res.start + 1;
++ if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) {
++ printk(KERN_ERR DRV_NAME ": Error requesting memory region!\n");
++ return -EBUSY;
++ }
++ prv->regs = devm_ioremap(dev, regs_paddr, regs_size);
++ if (!prv->regs) {
++ printk(KERN_ERR DRV_NAME ": Error mapping memory region!\n");
++ return -ENOMEM;
++ }
++ prv->data_buffers=dma_alloc_coherent(NULL, DATA_BUFFER_MAX_SIZE,
++ &prv->data_buffers_phyaddr, GFP_KERNEL);
++ if(!prv->data_buffers)return -ENOMEM;
++ prv->ops_buffer=dma_alloc_coherent(NULL, SPARE_BUFFER_MAX_SIZE,
++ &prv->ops_buffer_phyaddr, GFP_KERNEL);
++ if(!prv->ops_buffer)
++ {
++ dma_free_coherent(NULL,DATA_BUFFER_MAX_SIZE,prv->data_buffers,prv->data_buffers_phyaddr);
++ return -ENOMEM;
++ }
++ /* Enable NFC clock */
++ prv->clk = clk_get(dev, "nfc_clk");
++ if (!prv->clk) {
++ printk(KERN_ERR DRV_NAME ": Unable to acquire NFC clock!\n");
++ retval = -ENODEV;
++ goto error;
++ }
++ clk_enable(prv->clk);
++ init_waitqueue_head(&prv->irq_waitq);
++ retval = devm_request_irq(dev, prv->irq, &mpc5125_nfc_irq,
++ 0, DRV_NAME, mtd);
++ if (retval) {
++ printk(KERN_ERR DRV_NAME ": Error requesting IRQ!\n");
++ goto error;
++ }
++
++ mtd->name = "MPC5125 NAND";
++ chip->write_page=chip_nand_write_page;
++ chip->dev_ready = mpc5125_nfc_dev_ready;
++ chip->cmdfunc = mpc5125_nfc_command;
++ chip->read_byte = mpc5125_nfc_read_byte;
++ chip->read_word = mpc5125_nfc_read_word;
++ chip->read_buf = mpc5125_nfc_read_buf;
++ chip->write_buf = mpc5125_nfc_write_buf;
++
++ chip->verify_buf = mpc5125_nfc_verify_buf;
++ chip->options = NAND_NO_AUTOINCR|NAND_USE_FLASH_BBT|NAND_SKIP_BBTSCAN;
++ chip->select_chip = ads5125_select_chip;
++ if(hardware_ecc)
++ {
++ chip->ecc.read_page = mpc5125_nand_read_page;
++ chip->ecc.write_page = mpc5125_nand_write_page;
++ chip->ecc.read_oob = mpc5125_nand_read_oob;
++ chip->ecc.write_oob = mpc5125_nand_write_oob;
++ chip->ecc.calculate = mpc5125_nand_calculate_ecc;
++ chip->ecc.hwctl = mpc5125_nand_enable_hwecc;
++ chip->ecc.correct = mpc5125_nand_correct_data;
++ chip->ecc.mode = NAND_ECC_HW;
++ chip->ecc.size = 512; /* RS-ECC is applied for both MAIN+SPARE not MAIN alone */
++ chip->ecc.bytes = 9; /* used for both main and spare area */
++ chip->ecc.layout=&nand_hw_eccoob_4k;
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_ECC_SRAM_ADDR_MASK,
++ CONFIG_ECC_SRAM_ADDR_SHIFT, (MPC5125_NFC_ECC_STATUS_ADD>>3)&0x00001ff);
++
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_ECC_MODE_MASK,
++ CONFIG_ECC_MODE_SHIFT, ECC_45_BYTE);
++
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_CMD_TIMEOUT_MASK,
++ CONFIG_CMD_TIMEOUT_SHIFT, 0xf);
++
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_ECC_SRAM_REQ_MASK,
++ CONFIG_ECC_SRAM_REQ_SHIFT, 1);
++
++ }
++ else
++ {
++#if NFC_DMA_ENABLE
++ chip->ecc.read_page_raw= nand_read_page_raw;
++ chip->ecc.write_page_raw= nand_write_page_raw;
++#endif
++ chip->ecc.mode = NAND_ECC_SOFT;
++ chip->ecc.layout=&nand_hw_eccoob_4k;
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_ECC_MODE_MASK,
++ CONFIG_ECC_MODE_SHIFT, ECC_BYPASS);
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_ECC_SRAM_REQ_MASK,
++ CONFIG_ECC_SRAM_REQ_SHIFT, 0);
++ }
++ memset( &prv->int_sem, 0, sizeof(struct semaphore));
++ sema_init( &prv->int_sem, 0 );
++
++ /* SET SECTOR SIZE */
++ nfc_write(mtd, NFC_SECTOR_SIZE,PAGE_virtual_2K);
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_PAGE_CNT_MASK,
++ CONFIG_PAGE_CNT_SHIFT, 2);
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_ADDR_AUTO_INCR_MASK,
++ CONFIG_ADDR_AUTO_INCR_SHIFT, 0);
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_BUFNO_AUTO_INCR_MASK,
++ CONFIG_BUFNO_AUTO_INCR_SHIFT, 1);
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_16BIT_MASK,
++ CONFIG_16BIT_SHIFT, 0);
++#if NFC_DMA_ENABLE
++ nfc_set_field(mtd,NFC_DMA_CONFIG,DMA_CONFIG_DMA1_CNT_MASK,
++ DMA_CONFIG_DMA1_CNT_SHIFT,PAGE_2K);
++ nfc_set_field(mtd,NFC_DMA_CONFIG,DMA_CONFIG_DMA2_CNT_MASK,
++ DMA_CONFIG_DMA2_CNT_SHIFT,0x40);
++ nfc_set_field(mtd,NFC_DMA_CONFIG,DMA_CONFIG_DMA1_ACT_MASK,
++ DMA_CONFIG_DMA1_ACT_SHIFT,1);
++ nfc_set_field(mtd,NFC_DMA_CONFIG,DMA_CONFIG_DMA2_OFFSET_MASK,
++ DMA_CONFIG_DMA2_OFFSET_SHIFT,(PAGE_2K>>1));
++ nfc_set_field(mtd,NFC_DMA_CONFIG,DMA_CONFIG_DMA2_ACT_MASK,
++ DMA_CONFIG_DMA2_ACT_SHIFT,1);
++#endif
++ /* SET FAST_FLASH = 1 */
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_FAST_FLASH_MASK,
++ CONFIG_FAST_FLASH_SHIFT, 1);
++ nfc_set_field(mtd, NFC_FLASH_CONFIG,
++ CONFIG_BOOT_MODE_MASK,
++ CONFIG_BOOT_MODE_SHIFT, 0);
++ /* Detect NAND chips */
++ if (nand_scan(mtd, *chips_no)) {
++ printk(KERN_ERR DRV_NAME ": NAND Flash not found !\n");
++ devm_free_irq(dev, prv->irq, mtd);
++ retval = -ENXIO;
++ goto error;
++ }
++ dev_set_drvdata(dev, mtd);
++
++
++ /* Register the partitions */
++#ifdef CONFIG_MTD_PARTITIONS
++ prv->nr_parts =
++ parse_mtd_partitions(mtd, mpc5125_nfc_pprobes, &prv->parts, 0);
++ if (prv->nr_parts > 0)
++ add_mtd_partitions(mtd, prv->parts, prv->nr_parts);
++ else if ((prv->nr_parts = parse_flash_partitions(mtd, dn)) > 0) {
++ dev_info(dev, "Using OF partition info\n");
++ add_mtd_partitions(mtd, prv->parts, prv->nr_parts);
++ } else
++#endif
++ {
++ pr_info("Registering %s as whole device\n", mtd->name);
++ add_mtd_device(mtd);
++ }
++ if (retval) {
++ printk(KERN_ERR DRV_NAME ": Error adding MTD device!\n");
++ devm_free_irq(dev, prv->irq, mtd);
++ goto error;
++ }
++ return 0;
++error:
++ dma_free_coherent(NULL,DATA_BUFFER_MAX_SIZE,prv->data_buffers,prv->data_buffers_phyaddr);
++ dma_free_coherent(NULL,SPARE_BUFFER_MAX_SIZE,prv->ops_buffer,prv->ops_buffer_phyaddr);
++ mpc5125_nfc_free(dev, mtd);
++ return retval;
++}
++
++static int __exit mpc5125_nfc_remove(struct of_device *op)
++{
++ struct device *dev = &op->dev;
++ struct mtd_info *mtd = dev_get_drvdata(dev);
++ struct nand_chip *chip = mtd->priv;
++ struct mpc5125_nfc_prv *prv = chip->priv;
++
++ nand_release(mtd);
++ devm_free_irq(dev, prv->irq, mtd);
++ dma_free_coherent(NULL,DATA_BUFFER_MAX_SIZE,prv->data_buffers,prv->data_buffers_phyaddr);
++ dma_free_coherent(NULL,SPARE_BUFFER_MAX_SIZE,prv->ops_buffer,prv->ops_buffer_phyaddr);
++ mpc5125_nfc_free(dev, mtd);
++
++ return 0;
++}
++
++static struct of_device_id mpc5125_nfc_match[] = {
++ { .compatible = "fsl,mpc5125-nfc", },
++ {},
++};
++
++static struct of_platform_driver mpc5125_nfc_driver = {
++ .owner = THIS_MODULE,
++ .name = DRV_NAME,
++ .match_table = mpc5125_nfc_match,
++ .probe = mpc5125_nfc_probe,
++ .remove = __exit_p(mpc5125_nfc_remove),
++ .suspend = NULL,
++ .resume = NULL,
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init mpc5125_nfc_init(void)
++{
++ pr_info("MPC5125 MTD nand Driver %s\n", DRV_VERSION);
++ if (of_register_platform_driver(&mpc5125_nfc_driver) != 0) {
++ printk(KERN_ERR DRV_NAME ": Driver register failed!\n");
++ return -ENODEV;
++ }
++ return 0;
++}
++
++static void __exit mpc5125_nfc_cleanup(void)
++{
++ of_unregister_platform_driver(&mpc5125_nfc_driver);
++}
++
++module_init(mpc5125_nfc_init);
++module_exit(mpc5125_nfc_cleanup);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("MPC5125 NAND MTD driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
+diff -Naur linux-2.6.29/drivers/mtd/nand/nand_ids.c linux-2.6.29-v2010041601/drivers/mtd/nand/nand_ids.c
+--- linux-2.6.29/drivers/mtd/nand/nand_ids.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/mtd/nand/nand_ids.c 2010-04-13 20:23:26.000000000 +0200
+@@ -65,6 +65,7 @@
+ {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
++ {"NAND 4GiB 3,3V 8-bit", 0x68, 0x1000, 0x1000, 0x100000, 0x00},
+
+ /*
+ * These are the new chips with large page size. The pagesize and the
+diff -Naur linux-2.6.29/drivers/net/can/Kconfig linux-2.6.29-v2010041601/drivers/net/can/Kconfig
+--- linux-2.6.29/drivers/net/can/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/can/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -22,4 +22,24 @@
+ a problem with CAN support and want to see more of what is going
+ on.
+
++config CAN_MSCAN
++ depends on CAN && (PPC || M68K || M68KNOMMU)
++ tristate "Support for a Freescale MSCAN based chips"
++ ---help---
++ The Motorola Scalable Controller Area Network (MSCAN) definition
++ is based on the MSCAN12 definition which is the specific
++ implementation of the Motorola Scalable CAN concept targeted for
++ the Motorola MC68HC12 Microcontroller Family.
++
++config CAN_MPC52XX
++ tristate "Freescale MPC5200/MPC5121 onboard CAN controller"
++ depends on CAN_MSCAN && (PPC_MPC52xx || PPC_52xx || PPC_MPC5121 || PPC_MPC5125)
++ default LITE5200
++ ---help---
++ If you say yes here you get support for Freescale MPC5200/MPC5121
++ onboard dualCAN controller.
++
++ This driver can also be built as a module. If so, the module
++ will be called mpc52xx_can.
++
+ endmenu
+diff -Naur linux-2.6.29/drivers/net/can/Makefile linux-2.6.29-v2010041601/drivers/net/can/Makefile
+--- linux-2.6.29/drivers/net/can/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/can/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -3,3 +3,4 @@
+ #
+
+ obj-$(CONFIG_CAN_VCAN) += vcan.o
++obj-$(CONFIG_CAN_MSCAN) += mscan/
+diff -Naur linux-2.6.29/drivers/net/can/mscan/Makefile linux-2.6.29-v2010041601/drivers/net/can/mscan/Makefile
+--- linux-2.6.29/drivers/net/can/mscan/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/can/mscan/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_CAN_MPC52XX) += mscan-mpc52xx.o
++mscan-mpc52xx-objs := mscan.o mpc52xx_can.o
+diff -Naur linux-2.6.29/drivers/net/can/mscan/mpc52xx_can.c linux-2.6.29-v2010041601/drivers/net/can/mscan/mpc52xx_can.c
+--- linux-2.6.29/drivers/net/can/mscan/mpc52xx_can.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/can/mscan/mpc52xx_can.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,337 @@
++/*
++ * DESCRIPTION:
++ * CAN bus driver for the Freescale MPC52xx embedded CPU.
++ *
++ * AUTHOR:
++ * Andrey Volkov <avolkov@varma-el.com>
++ *
++ * COPYRIGHT:
++ * 2004-2005, Varma Electronics Oy
++ *
++ * LICENCE:
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * HISTORY:
++ * 2008-02-26 Add support for MPC512x
++ * Hongjun, Chen <hong-jun.chen@freescale.com>
++ * 2005-02-03 created
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/netdevice.h>
++#include <linux/can.h>
++#include <linux/can/dev.h>
++#include <asm/io.h>
++#include <asm/of_platform.h>
++#include <asm/mpc512x.h>
++#include <linux/clk.h>
++#include "mscan.h"
++
++#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
++
++RCSID("$Id$");
++
++#define PDEV_MAX 4
++
++struct platform_device *pdev[PDEV_MAX];
++
++static int __devinit mpc52xx_can_probe(struct platform_device *pdev)
++{
++ struct resource *mem;
++ struct net_device *dev;
++ struct mscan_platform_data *pdata = pdev->dev.platform_data;
++ struct can_priv *can;
++ u32 mem_size;
++ int ret = -ENODEV;
++
++ if (!pdata)
++ return ret;
++ dev = alloc_mscandev();
++ if (!dev)
++ return -ENOMEM;
++ can = netdev_priv(dev);
++
++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ dev->irq = platform_get_irq(pdev, 0);
++ if (!mem || !dev->irq)
++ goto req_error;
++
++ mem_size = mem->end - mem->start + 1;
++ if (!request_mem_region(mem->start, mem_size, pdev->dev.driver->name)) {
++ dev_err(&pdev->dev, "resource unavailable\n");
++ goto req_error;
++ }
++
++ SET_NETDEV_DEV(dev, &pdev->dev);
++
++ dev->base_addr = (unsigned long)ioremap_nocache(mem->start, mem_size);
++
++ if (!dev->base_addr) {
++ dev_err(&pdev->dev, "failed to map can port\n");
++ ret = -ENOMEM;
++ goto fail_map;
++ }
++
++ if (pdata->cpu_type == MPC512x_MSCAN) {
++ struct clk *mscan_clk, *port_clk;
++ char clk_name[15];
++
++ mscan_clk = clk_get(NULL, "mscan_clk");
++ if (!mscan_clk) {
++ dev_err(&pdev->dev, "can't get mscan clock!");
++ ret = -EINVAL;
++ goto fail_map;
++ }
++
++ sprintf(clk_name, "mscan%d_clk", pdata->port);
++ port_clk = clk_get(NULL, clk_name);
++
++ /* update clock rate for mpc5121e rev2 chip */
++ if (port_clk)
++ pdata->clock_frq = clk_get_rate(port_clk);
++
++ /* enable clock for mscan module */
++ clk_enable(mscan_clk);
++ }
++
++ can->can_sys_clock = pdata->clock_frq;
++
++ platform_set_drvdata(pdev, dev);
++
++ ret = register_mscandev(dev, pdata->clock_src);
++ if (ret >= 0) {
++ dev_info(&pdev->dev, "probe port 0x%lX done, clk rate:%d\n",
++ dev->base_addr, pdata->clock_frq);
++ return ret;
++ }
++
++ iounmap((unsigned long *)dev->base_addr);
++ fail_map:
++ release_mem_region(mem->start, mem_size);
++ req_error:
++ free_candev(dev);
++ dev_err(&pdev->dev, "probe failed\n");
++ return ret;
++}
++
++static int __devexit mpc52xx_can_remove(struct platform_device *pdev)
++{
++ struct net_device *dev = platform_get_drvdata(pdev);
++ struct resource *mem;
++
++ platform_set_drvdata(pdev, NULL);
++ unregister_mscandev(dev);
++
++ iounmap((volatile void __iomem *)dev->base_addr);
++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ release_mem_region(mem->start, mem->end - mem->start + 1);
++ free_candev(dev);
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static struct mscan_regs saved_regs;
++static int mpc52xx_can_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ struct net_device *dev = platform_get_drvdata(pdev);
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++
++ _memcpy_fromio(&saved_regs, regs, sizeof(*regs));
++
++ regs->canctl1 |= MSCAN_CANE;
++ regs->canctl1 &= ~MSCAN_LISTEN;
++ regs->canctl0 |= MSCAN_SLPRQ;
++ regs->canctl0 |= MSCAN_INITRQ;
++ mdelay(20);
++ regs->canctl0 &= ~MSCAN_INITRQ;
++ regs->canctl0 |= MSCAN_WUPE;
++ mdelay(20);
++ regs->canrier |= 0xff;
++
++ return 0;
++}
++
++static int mpc52xx_can_resume(struct platform_device *pdev)
++{
++ struct net_device *dev = platform_get_drvdata(pdev);
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++
++ regs->canctl0 |= MSCAN_INITRQ;
++ while ((regs->canctl1 & MSCAN_INITAK) == 0)
++ udelay(10);
++
++ regs->canctl1 = saved_regs.canctl1;
++ regs->canbtr0 = saved_regs.canbtr0;
++ regs->canbtr1 = saved_regs.canbtr1;
++ regs->canidac = saved_regs.canidac;
++
++ /* restore masks, buffers etc. */
++ _memcpy_toio(®s->canidar1_0, (void *)&saved_regs.canidar1_0,
++ sizeof(*regs) - offsetof(struct mscan_regs, canidar1_0));
++
++ regs->canctl0 &= ~MSCAN_INITRQ;
++ regs->cantbsel = saved_regs.cantbsel;
++ regs->canrier = saved_regs.canrier;
++ regs->cantier = saved_regs.cantier;
++ regs->canctl0 = saved_regs.canctl0;
++
++ regs->canrflg &= 0xc3;
++
++ return 0;
++}
++#endif
++
++static struct platform_driver mpc52xx_can_driver = {
++ .driver = {
++ .name = "fsl-mscan",
++ },
++ .probe = mpc52xx_can_probe,
++ .remove = __devexit_p(mpc52xx_can_remove),
++#ifdef CONFIG_PM
++ .suspend = mpc52xx_can_suspend,
++ .resume = mpc52xx_can_resume,
++#endif
++};
++
++#ifdef CONFIG_PPC_MERGE
++unsigned int fsl_find_ipb_freq(struct device_node *node)
++{
++ struct device_node *np;
++ const unsigned int *p_ipb_freq = NULL;
++
++ of_node_get(node);
++ while (node) {
++ p_ipb_freq = of_get_property(node, "bus-frequency", NULL);
++ if (p_ipb_freq)
++ break;
++
++ np = of_get_parent(node);
++ of_node_put(node);
++ node = np;
++ }
++ if (node)
++ of_node_put(node);
++
++ return p_ipb_freq ? *p_ipb_freq : 0;
++}
++
++static int __init mpc52xx_of_to_pdev(void)
++{
++ struct device_node *np = NULL;
++ unsigned int i;
++ int ret, type = -1, index = 0;
++ int *port;
++ char *mscan_comp_name[] = {"fsl,mpc5200-mscan",
++ "fsl,mpc5121rev2-mscan",
++ "fsl,mpc5121-mscan"};
++ int cpu_type[] = {MPC52xx_MSCAN, MPC512x_MSCAN, MPC512x_MSCAN};
++
++ for (i = 0; i < 3; i++) {
++ np = of_find_compatible_node(np, NULL, mscan_comp_name[i]);
++ if (np) {
++ type = cpu_type[i];
++ index = i;
++ of_node_put(np);
++ np = NULL;
++ break;
++ }
++ }
++
++ if (type != cpu_type[0] && type != cpu_type[1]) {
++ printk(KERN_ERR "%s: can't find any CAN devices\n", __func__);
++ return -1;
++ }
++
++ for (i = 0;
++ (np = of_find_compatible_node(np, NULL,
++ mscan_comp_name[index]));
++ i++) {
++ struct resource r[2] = { };
++ struct mscan_platform_data pdata;
++
++ if (i >= PDEV_MAX) {
++ printk(KERN_WARNING "%s: increase PDEV_MAX for more "
++ "than %i devices\n", __func__, PDEV_MAX);
++ break;
++ }
++
++ ret = of_address_to_resource(np, 0, &r[0]);
++ if (ret)
++ goto err;
++
++ of_irq_to_resource(np, 0, &r[1]);
++
++ pdev[i] =
++ platform_device_register_simple("fsl-mscan", i, r, 2);
++ if (IS_ERR(pdev[i])) {
++ ret = PTR_ERR(pdev[i]);
++ goto err;
++ }
++
++ pdata.clock_src = MSCAN_CLKSRC_BUS;
++ pdata.cpu_type = type;
++ pdata.clock_frq = fsl_find_ipb_freq(np);
++
++ if (pdata.cpu_type == MPC512x_MSCAN) {
++ port = (int *)of_get_property(np, "cell-index", NULL);
++ if (!port) {
++ printk(KERN_ERR "Err: can't find can port!\n");
++ goto err;
++ }
++ pdata.port = *port;
++ }
++
++ ret = platform_device_add_data(pdev[i], &pdata, sizeof(pdata));
++ if (ret)
++ goto err;
++ }
++ /*can1_tx psc9 pin 0*/
++ mpc5125_io_controller_set(0x4d,0x03);
++ /*can2_tx psc9 pin 1*/
++ mpc5125_io_controller_set(0x4e, 0x03);
++ return 0;
++ err:
++ return ret;
++}
++#else
++#define mscan_of_to_pdev()
++#endif
++
++int __init mpc52xx_can_init(void)
++{
++ mpc52xx_of_to_pdev();
++ printk(KERN_INFO "%s initializing\n", mpc52xx_can_driver.driver.name);
++ return platform_driver_register(&mpc52xx_can_driver);
++}
++
++void __exit mpc52xx_can_exit(void)
++{
++ int i;
++ platform_driver_unregister(&mpc52xx_can_driver);
++ for (i = 0; i < PDEV_MAX; i++)
++ platform_device_unregister(pdev[i]);
++ printk(KERN_INFO "%s unloaded\n", mpc52xx_can_driver.driver.name);
++}
++
++module_init(mpc52xx_can_init);
++module_exit(mpc52xx_can_exit);
++
++MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
++MODULE_DESCRIPTION("Freescale MPC5200/MPC512x CAN driver");
++MODULE_LICENSE("GPL v2");
+diff -Naur linux-2.6.29/drivers/net/can/mscan/mscan.c linux-2.6.29-v2010041601/drivers/net/can/mscan/mscan.c
+--- linux-2.6.29/drivers/net/can/mscan/mscan.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/can/mscan/mscan.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,718 @@
++/*
++ * mscan.c
++ *
++ * DESCRIPTION:
++ * CAN bus driver for the alone generic (as possible as) MSCAN controller.
++ *
++ * AUTHOR:
++ * Andrey Volkov <avolkov@varma-el.com>
++ *
++ * COPYRIGHT:
++ * 2005-2006, Varma Electronics Oy
++ *
++ * LICENCE:
++ * 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/kernel.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/if_arp.h>
++#include <linux/if_ether.h>
++#include <linux/can.h>
++#include <linux/list.h>
++#include <asm/io.h>
++#include <asm/of_platform.h>
++
++#include <linux/can/dev.h>
++#include <linux/can/error.h>
++#include "mscan.h"
++
++#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
++RCSID("$Id$");
++
++#define MSCAN_NORMAL_MODE 0
++#define MSCAN_SLEEP_MODE MSCAN_SLPRQ
++#define MSCAN_INIT_MODE (MSCAN_INITRQ | MSCAN_SLPRQ)
++#define MSCAN_POWEROFF_MODE (MSCAN_CSWAI | MSCAN_SLPRQ)
++#define MSCAN_SET_MODE_RETRIES 1000
++
++
++#define BTR0_BRP_MASK 0x3f
++#define BTR0_SJW_SHIFT 6
++#define BTR0_SJW_MASK (0x3 << BTR0_SJW_SHIFT)
++
++#define BTR1_TSEG1_MASK 0xf
++#define BTR1_TSEG2_SHIFT 4
++#define BTR1_TSEG2_MASK (0x7 << BTR1_TSEG2_SHIFT)
++#define BTR1_SAM_SHIFT 7
++
++#define BTR0_SET_BRP(brp) (((brp) - 1) & BTR0_BRP_MASK)
++#define BTR0_SET_SJW(sjw) ((((sjw) - 1) << BTR0_SJW_SHIFT) & \
++ BTR0_SJW_MASK)
++
++#define BTR1_SET_TSEG1(tseg1) (((tseg1) - 1) & BTR1_TSEG1_MASK)
++#define BTR1_SET_TSEG2(tseg2) ((((tseg2) - 1) << BTR1_TSEG2_SHIFT) & \
++ BTR1_TSEG2_MASK)
++#define BTR1_SET_SAM(sam) (((sam) & 1) << BTR1_SAM_SHIFT)
++
++struct mscan_state {
++ u8 mode;
++ u8 canrier;
++ u8 cantier;
++};
++
++#define TX_QUEUE_SIZE 3
++
++typedef struct {
++ struct list_head list;
++ u8 mask;
++} tx_queue_entry_t;
++
++struct mscan_priv {
++ struct can_priv can;
++ struct napi_struct napi;
++ struct net_device *netdev;
++ volatile unsigned long flags;
++ u8 shadow_statflg;
++ u8 shadow_canrier;
++ u8 cur_pri;
++ u8 tx_active;
++
++ struct list_head tx_head;
++ tx_queue_entry_t tx_queue[TX_QUEUE_SIZE];
++};
++
++#define F_RX_PROGRESS 0
++#define F_TX_PROGRESS 1
++#define F_TX_WAIT_ALL 2
++
++static int mscan_set_mode(struct net_device *dev, u8 mode)
++{
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++ struct mscan_priv *priv = netdev_priv(dev);
++ int ret = 0;
++ int i;
++ u8 canctl1;
++
++ if (mode != MSCAN_NORMAL_MODE) {
++ if (priv->tx_active) {
++ /* Abort transfers before going to sleep */
++ out_8(®s->cantarq, priv->tx_active);
++ /* Suppress TX done interrupts */
++ out_8(®s->cantier, 0);
++ }
++ canctl1 = in_8(®s->canctl1);
++ if ((mode & MSCAN_SLPRQ) && (canctl1 & MSCAN_SLPAK) == 0) {
++ out_8(®s->canctl0,in_8(®s->canctl0) | MSCAN_SLPRQ);
++ for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) {
++ out_8(®s->canctl0,in_8(®s->canctl0) | MSCAN_SLPRQ);
++ if (in_8(®s->canctl1) & MSCAN_SLPAK)
++ break;
++ udelay(100);
++ }
++ if (i >= MSCAN_SET_MODE_RETRIES)
++ ret = -ENODEV;
++ }
++ if (!ret && (mode & MSCAN_INITRQ)
++ && (canctl1 & MSCAN_INITAK) == 0) {
++ out_8(®s->canctl0,
++ in_8(®s->canctl0) | MSCAN_INITRQ);
++ for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) {
++ out_8(®s->canctl0,
++ in_8(®s->canctl0) | MSCAN_INITRQ);
++ if (in_8(®s->canctl1) & MSCAN_INITAK)
++ break;
++ }
++ if (i >= MSCAN_SET_MODE_RETRIES)
++ ret = -ENODEV;
++ }
++ if (!ret && (mode & MSCAN_CSWAI))
++ out_8(®s->canctl0,
++ in_8(®s->canctl0) | MSCAN_CSWAI);
++
++ } else {
++ canctl1 = in_8(®s->canctl1);
++ if (canctl1 & (MSCAN_SLPAK | MSCAN_INITAK)) {
++ out_8(®s->canctl0, in_8(®s->canctl0) &
++ ~(MSCAN_SLPRQ | MSCAN_INITRQ));
++ for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) {
++ out_8(®s->canctl0, in_8(®s->canctl0) &
++ ~(MSCAN_SLPRQ | MSCAN_INITRQ));
++ canctl1 = in_8(®s->canctl1);
++ if (!(canctl1 & (MSCAN_INITAK | MSCAN_SLPAK)))
++ break;
++ }
++ if (i >= MSCAN_SET_MODE_RETRIES)
++ ret = -ENODEV;
++ }
++ }
++ return ret;
++}
++
++static void mscan_push_state(struct net_device *dev, struct mscan_state *state)
++{
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++
++ state->mode = in_8(®s->canctl0) & (MSCAN_SLPRQ | MSCAN_INITRQ |
++ MSCAN_CSWAI);
++ state->canrier = in_8(®s->canrier);
++ state->cantier = in_8(®s->cantier);
++}
++
++static int mscan_pop_state(struct net_device *dev, struct mscan_state *state)
++{
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++
++ int ret;
++ ret = mscan_set_mode(dev, state->mode);
++ if (!ret) {
++ out_8(®s->canrier, state->canrier);
++ out_8(®s->cantier, state->cantier);
++ }
++ return ret;
++}
++
++static int mscan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct can_frame *frame = (struct can_frame *)skb->data;
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++ struct mscan_priv *priv = netdev_priv(dev);
++
++ int i, rtr, buf_id;
++ u32 can_id;
++
++ if (frame->can_dlc > 8)
++ return -EINVAL;
++
++ dev_dbg(ND2D(dev), "%s\n", __FUNCTION__);
++ out_8(®s->cantier, 0);
++
++ i = ~priv->tx_active & MSCAN_TXE;
++ buf_id = ffs(i) - 1;
++ switch (hweight8(i)) {
++ case 0:
++ netif_stop_queue(dev);
++ dev_err(ND2D(dev), "BUG! Tx Ring full when queue awake!\n");
++ return NETDEV_TX_BUSY;
++ case 1:
++ /* if buf_id < 3, then current frame will be send out of order,
++ since buffer with lower id have higher priority (hell..) */
++ if (buf_id < 3)
++ priv->cur_pri++;
++ if (priv->cur_pri == 0xff)
++ set_bit(F_TX_WAIT_ALL, &priv->flags);
++ netif_stop_queue(dev);
++ case 2:
++ set_bit(F_TX_PROGRESS, &priv->flags);
++ }
++ out_8(®s->cantbsel, i);
++
++ rtr = frame->can_id & CAN_RTR_FLAG;
++
++ if (frame->can_id & CAN_EFF_FLAG) {
++ dev_dbg(ND2D(dev), "sending extended frame\n");
++
++ can_id = (frame->can_id & CAN_EFF_MASK) << 1;
++ if (rtr)
++ can_id |= 1;
++ out_be16(®s->tx.idr3_2, can_id);
++
++ can_id >>= 16;
++ can_id = (can_id & 0x7) | ((can_id << 2) & 0xffe0) | (3 << 3);
++ } else {
++ dev_dbg(ND2D(dev), "sending standard frame\n");
++ can_id = (frame->can_id & CAN_SFF_MASK) << 5;
++ if (rtr)
++ can_id |= 1 << 4;
++ }
++ out_be16(®s->tx.idr1_0, can_id);
++
++ if (!rtr) {
++ volatile void __iomem *data = ®s->tx.dsr1_0;
++ u16 *payload = (u16 *) frame->data;
++ /*Its safe to write into dsr[dlc+1] */
++ for (i = 0; i < (frame->can_dlc + 1) / 2; i++) {
++ out_be16(data, *payload++);
++ data += 2 + _MSCAN_RESERVED_DSR_SIZE;
++ }
++ }
++
++ out_8(®s->tx.dlr, frame->can_dlc);
++ out_8(®s->tx.tbpr, priv->cur_pri);
++
++ /* Start transmission. */
++ out_8(®s->cantflg, 1 << buf_id);
++
++ if (!test_bit(F_TX_PROGRESS, &priv->flags))
++ dev->trans_start = jiffies;
++
++ list_add_tail(&priv->tx_queue[buf_id].list, &priv->tx_head);
++
++ kfree_skb(skb);
++
++ /* Enable interrupt. */
++ priv->tx_active |= 1 << buf_id;
++ out_8(®s->cantier, priv->tx_active);
++
++ return NETDEV_TX_OK;
++}
++
++static void mscan_tx_timeout(struct net_device *dev)
++{
++ struct sk_buff *skb;
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++ struct mscan_priv *priv = netdev_priv(dev);
++ struct can_frame *frame;
++ u8 mask;
++
++ printk("%s\n", __FUNCTION__);
++
++ out_8(®s->cantier, 0);
++
++ mask = list_entry(priv->tx_head.next, tx_queue_entry_t, list)->mask;
++ dev->trans_start = jiffies;
++ out_8(®s->cantarq, mask);
++ out_8(®s->cantier, priv->tx_active);
++
++ skb = dev_alloc_skb(sizeof(struct can_frame));
++ if (!skb) {
++ if (printk_ratelimit())
++ dev_notice(ND2D(dev), "TIMEOUT packet dropped\n");
++ return;
++ }
++ frame = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
++
++ frame->can_id = CAN_ERR_FLAG | CAN_ERR_TX_TIMEOUT;
++ frame->can_dlc = CAN_ERR_DLC;
++
++ skb->dev = dev;
++ skb->protocol = __constant_htons(ETH_P_CAN);
++ skb->pkt_type = PACKET_BROADCAST;
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++
++ netif_rx(skb);
++
++}
++
++static can_state_t state_map[] = {
++ CAN_STATE_ACTIVE,
++ CAN_STATE_BUS_WARNING,
++ CAN_STATE_BUS_PASSIVE,
++ CAN_STATE_BUS_OFF
++};
++
++static inline int check_set_state(struct net_device *dev, u8 canrflg)
++{
++ struct mscan_priv *priv = netdev_priv(dev);
++ can_state_t state;
++ int ret = 0;
++
++ if (!(canrflg & MSCAN_CSCIF) || priv->can.state > CAN_STATE_BUS_OFF)
++ return 0;
++
++ state =
++ state_map[max(MSCAN_STATE_RX(canrflg), MSCAN_STATE_TX(canrflg))];
++ if (priv->can.state < state)
++ ret = 1;
++ if (state == CAN_STATE_BUS_OFF)
++ netif_carrier_off(dev);
++ else if (priv->can.state == CAN_STATE_BUS_OFF
++ && state != CAN_STATE_BUS_OFF)
++ netif_carrier_on(dev);
++ priv->can.state = state;
++ return ret;
++}
++
++int mscan_rx_poll(struct napi_struct *napi, int budget)
++{
++ struct mscan_priv *priv = container_of(napi, struct mscan_priv, napi);
++ struct net_device *dev = priv->netdev;
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++ int npackets = 0, quota = budget;
++ int ret = 1;
++ struct sk_buff *skb;
++ struct can_frame *frame;
++ u32 can_id;
++ u8 canrflg;
++ int i;
++
++ while (npackets < quota && ((canrflg = in_8(®s->canrflg)) &
++ (MSCAN_RXF | MSCAN_ERR_IF))) {
++ skb = dev_alloc_skb(sizeof(struct can_frame));
++ if (!skb) {
++ if (printk_ratelimit())
++ dev_notice(ND2D(dev), "packet dropped\n");
++ out_8(®s->canrflg, canrflg);
++ continue;
++ }
++
++ frame = (struct can_frame *)skb_put(skb,
++ sizeof(struct can_frame));
++
++ if (canrflg & MSCAN_RXF) {
++ can_id = in_be16(®s->rx.idr1_0);
++ if (can_id & (1 << 3)) {
++ frame->can_id = CAN_EFF_FLAG;
++ can_id = ((can_id << 16) |
++ in_be16(®s->rx.idr3_2));
++ can_id = ((can_id & 0xffe00000) |
++ ((can_id & 0x7ffff) << 2)) >> 2;
++ } else {
++ can_id >>= 4;
++ frame->can_id = 0;
++ }
++
++ frame->can_id |= can_id >> 1;
++ if (can_id & 1)
++ frame->can_id |= CAN_RTR_FLAG;
++ frame->can_dlc = in_8(®s->rx.dlr) & 0xf;
++
++ if (!(frame->can_id & CAN_RTR_FLAG)) {
++ volatile void __iomem *data = ®s->rx.dsr1_0;
++ u16 *payload = (u16 *) frame->data;
++ for (i = 0; i < (frame->can_dlc + 1) / 2; i++) {
++ *payload++ = in_be16(data);
++ data += 2 + _MSCAN_RESERVED_DSR_SIZE;
++ }
++ }
++
++ dev_dbg(ND2D(dev),
++ "received pkt: id: %u dlc: %u data: ",
++ frame->can_id, frame->can_dlc);
++#ifdef DEBUG
++ for (i = 0;
++ i < frame->can_dlc; i++)
++ printk("%02x ", frame->data[i]);
++ printk("\n");
++#endif
++
++ out_8(®s->canrflg, MSCAN_RXF);
++ dev->last_rx = jiffies;
++ } else if (canrflg & MSCAN_ERR_IF) {
++ frame->can_id = CAN_ERR_FLAG;
++
++ if (canrflg & MSCAN_OVRIF) {
++ frame->can_id |= CAN_ERR_CRTL;
++ frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
++ } else
++ frame->data[1] = 0;
++
++ if (check_set_state(dev, canrflg)) {
++ frame->can_id |= CAN_ERR_CRTL;
++ switch (priv->can.state) {
++ case CAN_STATE_BUS_WARNING:
++ if ((priv->shadow_statflg &
++ MSCAN_RSTAT_MSK) <
++ (canrflg & MSCAN_RSTAT_MSK))
++ frame->data[1] |=
++ CAN_ERR_CRTL_RX_WARNING;
++
++ if ((priv->shadow_statflg &
++ MSCAN_TSTAT_MSK) <
++ (canrflg & MSCAN_TSTAT_MSK))
++ frame->data[1] |=
++ CAN_ERR_CRTL_TX_WARNING;
++ break;
++ case CAN_STATE_BUS_PASSIVE:
++ frame->data[1] |=
++ CAN_ERR_CRTL_RX_PASSIVE;
++ break;
++ case CAN_STATE_BUS_OFF:
++ frame->can_id |= CAN_ERR_BUSOFF;
++ frame->can_id &= ~CAN_ERR_CRTL;
++ break;
++ }
++ }
++ priv->shadow_statflg = canrflg & MSCAN_STAT_MSK;
++ frame->can_dlc = CAN_ERR_DLC;
++ out_8(®s->canrflg, MSCAN_ERR_IF);
++ }
++
++ npackets++;
++ skb->dev = dev;
++ skb->protocol = __constant_htons(ETH_P_CAN);
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++ netif_receive_skb(skb);
++ }
++
++ if (!(in_8(®s->canrflg) & (MSCAN_RXF | MSCAN_ERR_IF))) {
++ netif_rx_complete(napi);
++ clear_bit(F_RX_PROGRESS, &priv->flags);
++ out_8(®s->canrier,
++ in_8(®s->canrier) | MSCAN_ERR_IF | MSCAN_RXFIE);
++ ret = 0;
++ }
++ return ret;
++}
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++static irqreturn_t mscan_isr(int irq, void *dev_id, struct pt_regs *r)
++#else
++static irqreturn_t mscan_isr(int irq, void *dev_id)
++#endif
++{
++ struct net_device *dev = (struct net_device *)dev_id;
++ struct mscan_priv *priv = netdev_priv(dev);
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++ u8 cantflg, canrflg;
++ irqreturn_t ret = IRQ_NONE;
++
++ if (in_8(®s->cantier) & MSCAN_TXE) {
++ struct list_head *tmp, *pos;
++
++ cantflg = in_8(®s->cantflg) & MSCAN_TXE;
++
++ list_for_each_safe(pos, tmp, &priv->tx_head) {
++ tx_queue_entry_t *entry =
++ list_entry(pos, tx_queue_entry_t, list);
++ u8 mask = entry->mask;
++
++ if (!(cantflg & mask))
++ continue;
++
++ if (in_8(®s->cantaak) & mask) {
++ priv->can.can_stats.error_warning++;
++ } else {
++ out_8(®s->cantbsel, mask);
++ }
++ priv->tx_active &= ~mask;
++ list_del(pos);
++ }
++
++ if (list_empty(&priv->tx_head)) {
++ clear_bit(F_TX_WAIT_ALL, &priv->flags);
++ clear_bit(F_TX_PROGRESS, &priv->flags);
++ priv->cur_pri = 0;
++ } else
++ dev->trans_start = jiffies;
++
++ if (!test_bit(F_TX_WAIT_ALL, &priv->flags))
++ netif_wake_queue(dev);
++
++ out_8(®s->cantier, priv->tx_active);
++ ret = IRQ_HANDLED;
++ }
++
++ if ((((canrflg = in_8(®s->canrflg)) & ~MSCAN_STAT_MSK)) &&
++ !test_and_set_bit(F_RX_PROGRESS, &priv->flags)) {
++ if (check_set_state(dev, canrflg)) {
++ out_8(®s->canrflg, MSCAN_CSCIF);
++ ret = IRQ_HANDLED;
++ }
++
++ if (canrflg & ~MSCAN_STAT_MSK) {
++ priv->shadow_canrier = in_8(®s->canrier);
++ out_8(®s->canrier, 0);
++ clear_bit(NAPI_STATE_SCHED,
++ &priv->napi.state);
++ netif_rx_schedule(&priv->napi);
++ ret = IRQ_HANDLED;
++ } else
++ clear_bit(F_RX_PROGRESS, &priv->flags);
++ }
++
++ return ret;
++}
++
++static int mscan_do_set_mode(struct net_device *dev, can_mode_t mode)
++{
++ switch (mode) {
++ case CAN_MODE_SLEEP:
++ case CAN_MODE_STOP:
++ netif_stop_queue(dev);
++ printk("%s: CAN_MODE_STOP requested\n", __FUNCTION__);
++ mscan_set_mode(dev,
++ (mode ==
++ CAN_MODE_STOP) ? MSCAN_INIT_MODE :
++ MSCAN_SLEEP_MODE);
++ break;
++ case CAN_MODE_START:
++ printk("%s: CAN_MODE_START requested\n", __FUNCTION__);
++ mscan_set_mode(dev, MSCAN_NORMAL_MODE);
++ netif_wake_queue(dev);
++ break;
++
++ default:
++ return -EOPNOTSUPP;
++ }
++ return 0;
++}
++
++static int mscan_do_set_bit_time(struct net_device *dev,
++ struct can_bittime *bt)
++{
++ struct mscan_priv *priv = netdev_priv(dev);
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++ int ret = 0;
++ u8 reg;
++ struct mscan_state state;
++
++ if (bt->type != CAN_BITTIME_STD)
++ return -EINVAL;
++
++ spin_lock_irq(&priv->can.irq_lock);
++
++ mscan_push_state(dev, &state);
++ ret = mscan_set_mode(dev, MSCAN_INIT_MODE);
++ if (!ret) {
++ reg = BTR0_SET_BRP(bt->std.brp) | BTR0_SET_SJW(bt->std.sjw);
++ out_8(®s->canbtr0, reg);
++
++ reg = (BTR1_SET_TSEG1(bt->std.prop_seg + bt->std.phase_seg1) |
++ BTR1_SET_TSEG2(bt->std.phase_seg2) |
++ BTR1_SET_SAM(bt->std.sam));
++ out_8(®s->canbtr1, reg);
++
++ ret = mscan_pop_state(dev, &state);
++ }
++
++ spin_unlock_irq(&priv->can.irq_lock);
++ return ret;
++}
++
++static int mscan_open(struct net_device *dev)
++{
++ int ret;
++ struct mscan_priv *priv = netdev_priv(dev);
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
++ ret = request_irq(dev->irq, mscan_isr, SA_SHIRQ, dev->name, dev);
++#else
++ ret = request_irq(dev->irq, mscan_isr, IRQF_SHARED, dev->name, dev);
++#endif
++
++ if (ret < 0) {
++ printk(KERN_ERR "%s - failed to attach interrupt\n",
++ dev->name);
++ return ret;
++ }
++
++ INIT_LIST_HEAD(&priv->tx_head);
++ /* acceptance mask/acceptance code (accept everything) */
++ out_be16(®s->canidar1_0, 0);
++ out_be16(®s->canidar3_2, 0);
++ out_be16(®s->canidar5_4, 0);
++ out_be16(®s->canidar7_6, 0);
++
++ out_be16(®s->canidmr1_0, 0xffff);
++ out_be16(®s->canidmr3_2, 0xffff);
++ out_be16(®s->canidmr5_4, 0xffff);
++ out_be16(®s->canidmr7_6, 0xffff);
++ /* Two 32 bit Acceptance Filters */
++ out_8(®s->canidac, MSCAN_AF_32BIT);
++
++ out_8(®s->canctl1, in_8(®s->canctl1) & ~MSCAN_LISTEN);
++ mscan_set_mode(dev, MSCAN_NORMAL_MODE);
++
++ priv->shadow_statflg = in_8(®s->canrflg) & MSCAN_STAT_MSK;
++ priv->cur_pri = 0;
++ priv->tx_active = 0;
++
++ out_8(®s->cantier, 0);
++ /* Enable receive interrupts. */
++ out_8(®s->canrier, MSCAN_OVRIE | MSCAN_RXFIE | MSCAN_CSCIE |
++ MSCAN_RSTATE1 | MSCAN_RSTATE0 | MSCAN_TSTATE1 | MSCAN_TSTATE0);
++
++ netif_start_queue(dev);
++
++ return 0;
++}
++
++static int mscan_close(struct net_device *dev)
++{
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++
++ netif_stop_queue(dev);
++
++ /* disable interrupts */
++ out_8(®s->cantier, 0);
++ out_8(®s->canrier, 0);
++ free_irq(dev->irq, dev);
++
++ mscan_set_mode(dev, MSCAN_INIT_MODE);
++ return 0;
++}
++
++int register_mscandev(struct net_device *dev, int clock_src)
++{
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++ u8 ctl1;
++
++ ctl1 = in_8(®s->canctl1);
++ if (clock_src)
++ ctl1 |= MSCAN_CLKSRC;
++ else
++ ctl1 &= ~MSCAN_CLKSRC;
++
++ ctl1 |= MSCAN_CANE;
++ out_8(®s->canctl1, ctl1);
++ udelay(100);
++
++ mscan_set_mode(dev, MSCAN_INIT_MODE);
++
++ return register_netdev(dev);
++}
++
++EXPORT_SYMBOL(register_mscandev);
++
++void unregister_mscandev(struct net_device *dev)
++{
++ struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
++ mscan_set_mode(dev, MSCAN_INIT_MODE);
++ out_8(®s->canctl1, in_8(®s->canctl1) & ~MSCAN_CANE);
++ unregister_netdev(dev);
++}
++
++EXPORT_SYMBOL(unregister_mscandev);
++
++struct net_device *alloc_mscandev(void)
++{
++ struct net_device *dev;
++ struct mscan_priv *priv;
++ int i;
++
++ dev = alloc_candev(sizeof(struct mscan_priv));
++ if (!dev)
++ return NULL;
++ priv = netdev_priv(dev);
++
++ priv->netdev = dev;
++ dev->watchdog_timeo = MSCAN_WATCHDOG_TIMEOUT;
++ dev->open = mscan_open;
++ dev->stop = mscan_close;
++ dev->hard_start_xmit = mscan_hard_start_xmit;
++ dev->tx_timeout = mscan_tx_timeout;
++
++ netif_napi_add(dev, &priv->napi, mscan_rx_poll, 8);
++
++ priv->can.do_set_bit_time = mscan_do_set_bit_time;
++ priv->can.do_set_mode = mscan_do_set_mode;
++
++ for (i = 0; i < TX_QUEUE_SIZE; i++)
++ priv->tx_queue[i].mask = 1 << i;
++
++ return dev;
++}
++
++EXPORT_SYMBOL(alloc_mscandev);
++
++MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("CAN port driver for a mscan based chips");
+diff -Naur linux-2.6.29/drivers/net/can/mscan/mscan.h linux-2.6.29-v2010041601/drivers/net/can/mscan/mscan.h
+--- linux-2.6.29/drivers/net/can/mscan/mscan.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/can/mscan/mscan.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,271 @@
++/*
++ * $Id$
++ *
++ * DESCRIPTION:
++ * Definitions of consts/structs to drive the Freescale MSCAN.
++ *
++ * AUTHOR:
++ * Andrey Volkov <avolkov@varma-el.com>
++ *
++ * COPYRIGHT:
++ * 2004-2006, Varma Electronics Oy
++ *
++ * LICENCE:
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#ifndef __MSCAN_H__
++#define __MSCAN_H__
++
++#include <linux/autoconf.h>
++#include <asm/types.h>
++
++/* MSCAN control register 0 (CANCTL0) bits */
++#define MSCAN_RXFRM 0x80
++#define MSCAN_RXACT 0x40
++#define MSCAN_CSWAI 0x20
++#define MSCAN_SYNCH 0x10
++#define MSCAN_TIME 0x08
++#define MSCAN_WUPE 0x04
++#define MSCAN_SLPRQ 0x02
++#define MSCAN_INITRQ 0x01
++
++/* MSCAN control register 1 (CANCTL1) bits */
++#define MSCAN_CANE 0x80
++#define MSCAN_CLKSRC 0x40
++#define MSCAN_LOOPB 0x20
++#define MSCAN_LISTEN 0x10
++#define MSCAN_WUPM 0x04
++#define MSCAN_SLPAK 0x02
++#define MSCAN_INITAK 0x01
++
++#ifdef CONFIG_PPC_MPC52xx
++#define MSCAN_CLKSRC_BUS 0
++#define MSCAN_CLKSRC_XTAL MSCAN_CLKSRC
++#else
++#define MSCAN_CLKSRC_BUS MSCAN_CLKSRC
++#define MSCAN_CLKSRC_XTAL 0
++#endif
++
++/* MSCAN receiver flag register (CANRFLG) bits */
++#define MSCAN_WUPIF 0x80
++#define MSCAN_CSCIF 0x40
++#define MSCAN_RSTAT1 0x20
++#define MSCAN_RSTAT0 0x10
++#define MSCAN_TSTAT1 0x08
++#define MSCAN_TSTAT0 0x04
++#define MSCAN_OVRIF 0x02
++#define MSCAN_RXF 0x01
++#define MSCAN_ERR_IF (MSCAN_OVRIF | MSCAN_CSCIF)
++#define MSCAN_RSTAT_MSK (MSCAN_RSTAT1 | MSCAN_RSTAT0)
++#define MSCAN_TSTAT_MSK (MSCAN_TSTAT1 | MSCAN_TSTAT0)
++#define MSCAN_STAT_MSK (MSCAN_RSTAT_MSK | MSCAN_TSTAT_MSK)
++
++#define MSCAN_STATE_BUS_OFF (MSCAN_RSTAT1 | MSCAN_RSTAT0 | \
++ MSCAN_TSTAT1 | MSCAN_TSTAT0)
++#define MSCAN_STATE_TX(canrflg) (((canrflg)&MSCAN_TSTAT_MSK)>>2)
++#define MSCAN_STATE_RX(canrflg) (((canrflg)&MSCAN_RSTAT_MSK)>>4)
++#define MSCAN_STATE_ACTIVE 0
++#define MSCAN_STATE_WARNING 1
++#define MSCAN_STATE_PASSIVE 2
++#define MSCAN_STATE_BUSOFF 3
++
++/* MSCAN receiver interrupt enable register (CANRIER) bits */
++#define MSCAN_WUPIE 0x80
++#define MSCAN_CSCIE 0x40
++#define MSCAN_RSTATE1 0x20
++#define MSCAN_RSTATE0 0x10
++#define MSCAN_TSTATE1 0x08
++#define MSCAN_TSTATE0 0x04
++#define MSCAN_OVRIE 0x02
++#define MSCAN_RXFIE 0x01
++
++/* MSCAN transmitter flag register (CANTFLG) bits */
++#define MSCAN_TXE2 0x04
++#define MSCAN_TXE1 0x02
++#define MSCAN_TXE0 0x01
++#define MSCAN_TXE (MSCAN_TXE2 | MSCAN_TXE1 | MSCAN_TXE0)
++
++/* MSCAN transmitter interrupt enable register (CANTIER) bits */
++#define MSCAN_TXIE2 0x04
++#define MSCAN_TXIE1 0x02
++#define MSCAN_TXIE0 0x01
++#define MSCAN_TXIE (MSCAN_TXIE2 | MSCAN_TXIE1 | MSCAN_TXIE0)
++
++/* MSCAN transmitter message abort request (CANTARQ) bits */
++#define MSCAN_ABTRQ2 0x04
++#define MSCAN_ABTRQ1 0x02
++#define MSCAN_ABTRQ0 0x01
++
++/* MSCAN transmitter message abort ack (CANTAAK) bits */
++#define MSCAN_ABTAK2 0x04
++#define MSCAN_ABTAK1 0x02
++#define MSCAN_ABTAK0 0x01
++
++/* MSCAN transmit buffer selection (CANTBSEL) bits */
++#define MSCAN_TX2 0x04
++#define MSCAN_TX1 0x02
++#define MSCAN_TX0 0x01
++
++/* MSCAN ID acceptance control register (CANIDAC) bits */
++#define MSCAN_IDAM1 0x20
++#define MSCAN_IDAM0 0x10
++#define MSCAN_IDHIT2 0x04
++#define MSCAN_IDHIT1 0x02
++#define MSCAN_IDHIT0 0x01
++
++#define MSCAN_AF_32BIT 0x00
++#define MSCAN_AF_16BIT MSCAN_IDAM0
++#define MSCAN_AF_8BIT MSCAN_IDAM1
++#define MSCAN_AF_CLOSED (MSCAN_IDAM0|MSCAN_IDAM1)
++#define MSCAN_AF_MASK (~(MSCAN_IDAM0|MSCAN_IDAM1))
++
++/* MSCAN Miscellaneous Register (CANMISC) bits */
++#define MSCAN_BOHOLD 0x01
++
++#if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC5121) || defined(CONFIG_PPC_MPC5125)
++#define _MSCAN_RESERVED_(n,num) u8 _res##n[num]
++#define _MSCAN_RESERVED_DSR_SIZE 2
++#else
++#define _MSCAN_RESERVED_(n,num)
++#define _MSCAN_RESERVED_DSR_SIZE 0
++#endif
++
++/* Structure of the hardware registers */
++struct mscan_regs {
++ /* (see doco S12MSCANV3/D) MPC5200/5121 MSCAN */
++ u8 canctl0; /* + 0x00 0x00 */
++ u8 canctl1; /* + 0x01 0x01 */
++ _MSCAN_RESERVED_(1, 2); /* + 0x02 */
++ u8 canbtr0; /* + 0x04 0x02 */
++ u8 canbtr1; /* + 0x05 0x03 */
++ _MSCAN_RESERVED_(2, 2); /* + 0x06 */
++ u8 canrflg; /* + 0x08 0x04 */
++ u8 canrier; /* + 0x09 0x05 */
++ _MSCAN_RESERVED_(3, 2); /* + 0x0a */
++ u8 cantflg; /* + 0x0c 0x06 */
++ u8 cantier; /* + 0x0d 0x07 */
++ _MSCAN_RESERVED_(4, 2); /* + 0x0e */
++ u8 cantarq; /* + 0x10 0x08 */
++ u8 cantaak; /* + 0x11 0x09 */
++ _MSCAN_RESERVED_(5, 2); /* + 0x12 */
++ u8 cantbsel; /* + 0x14 0x0a */
++ u8 canidac; /* + 0x15 0x0b */
++ u8 reserved; /* + 0x16 0x0c */
++#ifdef CONFIG_PPC_MPC5125
++ u8 reserved2[2]; /* 0x17 0x18*/
++ u8 canmisc; /* 0x19*/
++ _MSCAN_RESERVED_(6, 2); /*0x1a 0x1b*/
++#else
++#ifndef CONFIG_PPC_MPC5121
++ _MSCAN_RESERVED_(6, 5); /* + 0x17 */
++#ifndef CONFIG_PPC_MPC52xx
++ u8 canmisc; /* 0x0d */
++#endif
++#else /* CONFIG_PPC_MPC5121 */
++ u8 reserved2; /* 0x17 */
++ u8 cantest; /* 0x18 */
++ u8 canmisc; /* 0x19 */
++ _MSCAN_RESERVED_(6, 2); /* 0x1a */
++#endif
++#endif
++ u8 canrxerr; /* + 0x1c 0x0e */
++ u8 cantxerr; /* + 0x1d 0x0f */
++ _MSCAN_RESERVED_(7, 2); /* + 0x1e */
++ u16 canidar1_0; /* + 0x20 0x10 */
++ _MSCAN_RESERVED_(8, 2); /* + 0x22 */
++ u16 canidar3_2; /* + 0x24 0x12 */
++ _MSCAN_RESERVED_(9, 2); /* + 0x26 */
++ u16 canidmr1_0; /* + 0x28 0x14 */
++ _MSCAN_RESERVED_(10, 2); /* + 0x2a */
++ u16 canidmr3_2; /* + 0x2c 0x16 */
++ _MSCAN_RESERVED_(11, 2); /* + 0x2e */
++ u16 canidar5_4; /* + 0x30 0x18 */
++ _MSCAN_RESERVED_(12, 2); /* + 0x32 */
++ u16 canidar7_6; /* + 0x34 0x1a */
++ _MSCAN_RESERVED_(13, 2); /* + 0x36 */
++ u16 canidmr5_4; /* + 0x38 0x1c */
++ _MSCAN_RESERVED_(14, 2); /* + 0x3a */
++ u16 canidmr7_6; /* + 0x3c 0x1e */
++ _MSCAN_RESERVED_(15, 2); /* + 0x3e */
++ struct {
++ u16 idr1_0; /* + 0x40 0x20 */
++ _MSCAN_RESERVED_(16, 2); /* + 0x42 */
++ u16 idr3_2; /* + 0x44 0x22 */
++ _MSCAN_RESERVED_(17, 2); /* + 0x46 */
++ u16 dsr1_0; /* + 0x48 0x24 */
++ _MSCAN_RESERVED_(18, 2); /* + 0x4a */
++ u16 dsr3_2; /* + 0x4c 0x26 */
++ _MSCAN_RESERVED_(19, 2); /* + 0x4e */
++ u16 dsr5_4; /* + 0x50 0x28 */
++ _MSCAN_RESERVED_(20, 2); /* + 0x52 */
++ u16 dsr7_6; /* + 0x54 0x2a */
++ _MSCAN_RESERVED_(21, 2); /* + 0x56 */
++ u8 dlr; /* + 0x58 0x2c */
++ u8:8; /* + 0x59 0x2d */
++ _MSCAN_RESERVED_(22, 2); /* + 0x5a */
++ u16 time; /* + 0x5c 0x2e */
++ } rx;
++#if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC5121) || defined(CONFIG_PPC_MPC5125)
++ _MSCAN_RESERVED_(23, 2); /* + 0x5e */
++#endif
++ struct {
++ u16 idr1_0; /* + 0x60 0x30 */
++ _MSCAN_RESERVED_(24, 2); /* + 0x62 */
++ u16 idr3_2; /* + 0x64 0x32 */
++ _MSCAN_RESERVED_(25, 2); /* + 0x66 */
++ u16 dsr1_0; /* + 0x68 0x34 */
++ _MSCAN_RESERVED_(26, 2); /* + 0x6a */
++ u16 dsr3_2; /* + 0x6c 0x36 */
++ _MSCAN_RESERVED_(27, 2); /* + 0x6e */
++ u16 dsr5_4; /* + 0x70 0x38 */
++ _MSCAN_RESERVED_(28, 2); /* + 0x72 */
++ u16 dsr7_6; /* + 0x74 0x3a */
++ _MSCAN_RESERVED_(29, 2); /* + 0x76 */
++ u8 dlr; /* + 0x78 0x3c */
++ u8 tbpr; /* + 0x79 0x3d */
++ _MSCAN_RESERVED_(30, 2); /* + 0x7a */
++ u16 time; /* + 0x7c 0x3e */
++ } tx;
++ _MSCAN_RESERVED_(31, 2); /* + 0x7e */
++} __attribute__ ((packed));
++
++#undef _MSCAN_RESERVED_
++#define MSCAN_REGION sizeof(struct mscan)
++
++#define MSCAN_WATCHDOG_TIMEOUT ((500*HZ)/1000)
++
++enum {
++ MPC52xx_MSCAN,
++ MPC512x_MSCAN,
++};
++
++struct mscan_platform_data {
++ u8 clock_src; /* MSCAN_CLKSRC_BUS or MSCAN_CLKSRC_XTAL */
++ u32 clock_frq; /* can ref. clock, in Hz */
++ u8 cpu_type; /* MPC52xx_MSCAN or MPC512x_MSCAN */
++ u8 port; /* Port number */
++};
++
++struct net_device *alloc_mscandev(void);
++/* @clock_src:
++ 1 = The MSCAN clock source is the onchip Bus Clock.
++ 0 = The MSCAN clock source is the chip Oscillator Clock.
++*/
++extern int register_mscandev(struct net_device *dev, int clock_src);
++extern void unregister_mscandev(struct net_device *dev);
++
++#endif /* __MSCAN_H__ */
+diff -Naur linux-2.6.29/drivers/net/fs_enet/fec.h linux-2.6.29-v2010041601/drivers/net/fs_enet/fec.h
+--- linux-2.6.29/drivers/net/fs_enet/fec.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/fs_enet/fec.h 2010-04-13 20:23:26.000000000 +0200
+@@ -26,6 +26,7 @@
+ #define FEC_RCNTRL_BC_REJ 0x00000010
+ #define FEC_RCNTRL_PROM 0x00000008
+ #define FEC_RCNTRL_MII_MODE 0x00000004
++#define FEC_RCNTRL_RMII_MODE 0x00000124
+ #define FEC_RCNTRL_DRT 0x00000002
+ #define FEC_RCNTRL_LOOP 0x00000001
+
+diff -Naur linux-2.6.29/drivers/net/fs_enet/fec_mpc5121.h linux-2.6.29-v2010041601/drivers/net/fs_enet/fec_mpc5121.h
+--- linux-2.6.29/drivers/net/fs_enet/fec_mpc5121.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/fs_enet/fec_mpc5121.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,121 @@
++/*
++ * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * Author: John Rigby, <jrigby@freescale.com>
++ *
++ * Modified version of drivers/net/fec.h:
++ *
++ * fec.h -- Fast Ethernet Controller for Motorola ColdFire SoC
++ * processors.
++ *
++ * (C) Copyright 2000-2005, Greg Ungerer (gerg@snapgear.com)
++ * (C) Copyright 2000-2001, Lineo (www.lineo.com)
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++#ifndef FEC_MPC5121_H
++#define FEC_MPC5121_H
++
++typedef struct fec {
++ u32 fec_reserved0;
++ u32 fec_ievent; /* Interrupt event reg */
++ u32 fec_imask; /* Interrupt mask reg */
++ u32 fec_reserved1;
++ u32 fec_r_des_active; /* Receive descriptor reg */
++ u32 fec_x_des_active; /* Transmit descriptor reg */
++ u32 fec_reserved2[3];
++ u32 fec_ecntrl; /* Ethernet control reg */
++ u32 fec_reserved3[6];
++ u32 fec_mii_data; /* MII manage frame reg */
++ u32 fec_mii_speed; /* MII speed control reg */
++ u32 fec_reserved4[7];
++ u32 fec_mib_ctrlstat; /* MIB control/status reg */
++ u32 fec_reserved5[7];
++ u32 fec_r_cntrl; /* Receive control reg */
++ u32 fec_reserved6[15];
++ u32 fec_x_cntrl; /* Transmit Control reg */
++ u32 fec_reserved7[7];
++ u32 fec_addr_low; /* Low 32bits MAC address */
++ u32 fec_addr_high; /* High 16bits MAC address */
++ u32 fec_opd; /* Opcode + Pause duration */
++ u32 fec_reserved8[10];
++ u32 fec_hash_table_high; /* High 32bits hash table */
++ u32 fec_hash_table_low; /* Low 32bits hash table */
++ u32 fec_grp_hash_table_high;/* High 32bits hash table */
++ u32 fec_grp_hash_table_low; /* Low 32bits hash table */
++ u32 fec_reserved9[7];
++ u32 fec_x_wmrk; /* FIFO transmit water mark */
++ u32 fec_reserved10;
++ u32 fec_r_bound; /* FIFO receive bound reg */
++ u32 fec_r_fstart; /* FIFO receive start reg */
++ u32 fec_reserved11[11];
++ u32 fec_r_des_start; /* Receive descriptor ring */
++ u32 fec_x_des_start; /* Transmit descriptor ring */
++ u32 fec_r_buff_size; /* Maximum receive buff size */
++ u32 fec_reserved12[26];
++ u32 fec_dma_control; /* DMA Endian and other ctrl */
++} fec_t;
++
++/*
++ * Define the buffer descriptor structure.
++ */
++typedef struct bufdesc {
++ unsigned short cbd_sc; /* Control and status info */
++ unsigned short cbd_datlen; /* Data length */
++ unsigned long cbd_bufaddr; /* Buffer address */
++} cbd_t;
++
++/*
++ * The following definitions courtesy of commproc.h, which where
++ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net).
++ */
++#define BD_SC_EMPTY ((ushort)0x8000) /* Recieve is empty */
++#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */
++#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */
++#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */
++#define BD_SC_CM ((ushort)0x0200) /* Continous mode */
++#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */
++#define BD_SC_P ((ushort)0x0100) /* xmt preamble */
++#define BD_SC_BR ((ushort)0x0020) /* Break received */
++#define BD_SC_FR ((ushort)0x0010) /* Framing error */
++#define BD_SC_PR ((ushort)0x0008) /* Parity error */
++#define BD_SC_OV ((ushort)0x0002) /* Overrun */
++#define BD_SC_CD ((ushort)0x0001) /* ?? */
++
++/* Buffer descriptor control/status used by Ethernet receive.
++*/
++#define BD_ENET_RX_EMPTY ((ushort)0x8000)
++#define BD_ENET_RX_WRAP ((ushort)0x2000)
++#define BD_ENET_RX_INTR ((ushort)0x1000)
++#define BD_ENET_RX_LAST ((ushort)0x0800)
++#define BD_ENET_RX_FIRST ((ushort)0x0400)
++#define BD_ENET_RX_MISS ((ushort)0x0100)
++#define BD_ENET_RX_LG ((ushort)0x0020)
++#define BD_ENET_RX_NO ((ushort)0x0010)
++#define BD_ENET_RX_SH ((ushort)0x0008)
++#define BD_ENET_RX_CR ((ushort)0x0004)
++#define BD_ENET_RX_OV ((ushort)0x0002)
++#define BD_ENET_RX_CL ((ushort)0x0001)
++#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */
++
++/* Buffer descriptor control/status used by Ethernet transmit.
++*/
++#define BD_ENET_TX_READY ((ushort)0x8000)
++#define BD_ENET_TX_PAD ((ushort)0x4000)
++#define BD_ENET_TX_WRAP ((ushort)0x2000)
++#define BD_ENET_TX_INTR ((ushort)0x1000)
++#define BD_ENET_TX_LAST ((ushort)0x0800)
++#define BD_ENET_TX_TC ((ushort)0x0400)
++#define BD_ENET_TX_DEF ((ushort)0x0200)
++#define BD_ENET_TX_HB ((ushort)0x0100)
++#define BD_ENET_TX_LC ((ushort)0x0080)
++#define BD_ENET_TX_RL ((ushort)0x0040)
++#define BD_ENET_TX_RCMASK ((ushort)0x003c)
++#define BD_ENET_TX_UN ((ushort)0x0002)
++#define BD_ENET_TX_CSL ((ushort)0x0001)
++#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */
++
++#endif /* FEC_MPC5121_H */
+diff -Naur linux-2.6.29/drivers/net/fs_enet/fs_enet.h linux-2.6.29-v2010041601/drivers/net/fs_enet/fs_enet.h
+--- linux-2.6.29/drivers/net/fs_enet/fs_enet.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/fs_enet/fs_enet.h 2010-04-13 20:23:26.000000000 +0200
+@@ -9,11 +9,17 @@
+ #include <linux/dma-mapping.h>
+
+ #include <linux/fs_enet_pd.h>
++#ifndef CONFIG_FS_ENET_MPC5121_FEC
+ #include <asm/fs_pd.h>
++#else
++#include "fec_mpc5121.h"
++#endif
+
+ #ifdef CONFIG_CPM1
+ #include <asm/cpm1.h>
++#endif
+
++#if defined(CONFIG_CPM1) || defined(CONFIG_FS_ENET_MPC5121_FEC)
+ struct fec_info {
+ fec_t __iomem *fecp;
+ u32 mii_speed;
+@@ -34,6 +40,8 @@
+ void (*adjust_link)(struct net_device *dev);
+ void (*restart)(struct net_device *dev);
+ void (*stop)(struct net_device *dev);
++ void (*pre_request_irq)(struct net_device *dev, int irq);
++ void (*post_free_irq)(struct net_device *dev, int irq);
+ void (*napi_clear_rx_event)(struct net_device *dev);
+ void (*napi_enable_rx)(struct net_device *dev);
+ void (*napi_disable_rx)(struct net_device *dev);
+@@ -136,7 +144,6 @@
+ };
+
+ /***************************************************************************/
+-
+ void fs_init_bds(struct net_device *dev);
+ void fs_cleanup_bds(struct net_device *dev);
+
+@@ -164,10 +171,10 @@
+ #define __cbd_in16(addr) __raw_readw(addr)
+ #else
+ /* for others play it safe */
+-#define __cbd_out32(addr, x) out_be32(addr, x)
+-#define __cbd_out16(addr, x) out_be16(addr, x)
+-#define __cbd_in32(addr) in_be32(addr)
+-#define __cbd_in16(addr) in_be16(addr)
++#define __cbd_out32(addr, x) out_be32((volatile void __iomem *)addr, x)
++#define __cbd_out16(addr, x) out_be16((volatile void __iomem *)addr, x)
++#define __cbd_in32(addr) in_be32((volatile void __iomem *)addr)
++#define __cbd_in16(addr) in_be16((volatile void __iomem *)addr)
+ #endif
+
+ /* write */
+diff -Naur linux-2.6.29/drivers/net/fs_enet/fs_enet-main.c linux-2.6.29-v2010041601/drivers/net/fs_enet/fs_enet-main.c
+--- linux-2.6.29/drivers/net/fs_enet/fs_enet-main.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/fs_enet/fs_enet-main.c 2010-04-13 20:23:26.000000000 +0200
+@@ -46,6 +46,14 @@
+
+ #include "fs_enet.h"
+
++#if 1
++#define DEBUG_PRINT()
++#define DEBUG_INFO(x...)
++#else
++#define DEBUG_PRINT() printk("----- %s:%d %s -----\n", __FILE__, __LINE__, __FUNCTION__)
++#define DEBUG_INFO(x...) printk(x)
++#endif
++
+ /*************************************************/
+
+ MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>");
+@@ -585,6 +593,33 @@
+
+ /**********************************************************************************/
+
++#define TX_ALIGN_WORKAROUND
++#ifdef TX_ALIGN_WORKAROUND
++static struct sk_buff *aligntxskb(struct net_device *dev, struct sk_buff *skb)
++{
++ struct sk_buff *skbn;
++ skbn = dev_alloc_skb(ENET_RX_FRSIZE+0x20);
++ if (skbn)
++ skb_align(skbn, 0x20);
++
++ if (!skbn) {
++ printk(KERN_WARNING DRV_MODULE_NAME
++ ": %s Memory squeeze, dropping tx packet.\n",
++ dev->name);
++ dev_kfree_skb_any(skb);
++ return NULL;
++ }
++
++ skb_copy_from_linear_data(skb, skbn->data, skb->len);
++ skb_put(skbn, skb->len);
++ dev_kfree_skb_any(skb);
++ return skbn;
++}
++#else
++#define aligntxskb(skb) skb
++#endif
++
++
+ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct fs_enet_private *fep = netdev_priv(dev);
+@@ -593,6 +628,7 @@
+ u16 sc;
+ unsigned long flags;
+
++ skb = aligntxskb(dev, skb);
+ spin_lock_irqsave(&fep->tx_lock, flags);
+
+ /*
+@@ -664,6 +700,23 @@
+ return NETDEV_TX_OK;
+ }
+
++static int fs_request_irq(struct net_device *dev, int irq, const char *name,
++ irq_handler_t irqf)
++{
++ struct fs_enet_private *fep = netdev_priv(dev);
++
++ (*fep->ops->pre_request_irq)(dev, irq);
++ return request_irq(irq, irqf, IRQF_SHARED, name, dev);
++}
++
++static void fs_free_irq(struct net_device *dev, int irq)
++{
++ struct fs_enet_private *fep = netdev_priv(dev);
++
++ free_irq(irq, dev);
++ (*fep->ops->post_free_irq)(dev, irq);
++}
++
+ static void fs_timeout(struct net_device *dev)
+ {
+ struct fs_enet_private *fep = netdev_priv(dev);
+@@ -926,11 +979,16 @@
+ {
+ struct fs_enet_private *fep = netdev_priv(dev);
+ struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data;
++ unsigned long flags;
++ int rc;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+- return phy_mii_ioctl(fep->phydev, mii, cmd);
++ spin_lock_irqsave(&fep->lock, flags);
++ rc = phy_mii_ioctl(fep->phydev, mii, cmd);
++ spin_unlock_irqrestore(&fep->lock, flags);
++ return rc;
+ }
+
+ extern int fs_mii_connect(struct net_device *dev);
+@@ -1100,9 +1158,8 @@
+ ndev->stop = fs_enet_close;
+ ndev->get_stats = fs_enet_get_stats;
+ ndev->set_multicast_list = fs_set_multicast_list;
+-#ifdef CONFIG_NET_POLL_CONTROLLER
+- ndev->poll_controller = fs_enet_netpoll;
+-#endif
++ SET_NETDEV_DEV(ndev, &ofdev->dev);
++
+ if (fpi->use_napi)
+ netif_napi_add(ndev, &fep->napi, fs_enet_rx_napi,
+ fpi->napi_weight);
+@@ -1118,7 +1175,12 @@
+ if (ret)
+ goto out_free_bd;
+
+- printk(KERN_INFO "%s: fs_enet: %pM\n", ndev->name, ndev->dev_addr);
++ printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n",
++ ndev->name,
++ ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
++ ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
++
++ DEBUG_PRINT();
+
+ return 0;
+
+@@ -1148,6 +1210,30 @@
+ free_netdev(ndev);
+ return 0;
+ }
++#ifdef CONFIG_PM
++static int fs_enet_suspend(struct of_device *op, pm_message_t state)
++{
++ struct net_device *ndev = dev_get_drvdata(&op->dev);
++
++ if (netif_running(ndev))
++ fs_enet_close(ndev);
++
++ return 0;
++}
++
++static int fs_enet_resume(struct of_device *op)
++{
++ struct net_device *ndev = dev_get_drvdata(&op->dev);
++
++ if (netif_running(ndev))
++ fs_enet_open(ndev);
++
++ return 0;
++}
++#else
++#define fs_enet_suspend NULL
++#define fs_enet_resume NULL
++#endif
+
+ static struct of_device_id fs_enet_match[] = {
+ #ifdef CONFIG_FS_ENET_HAS_SCC
+@@ -1155,10 +1241,6 @@
+ .compatible = "fsl,cpm1-scc-enet",
+ .data = (void *)&fs_scc_ops,
+ },
+- {
+- .compatible = "fsl,cpm2-scc-enet",
+- .data = (void *)&fs_scc_ops,
+- },
+ #endif
+ #ifdef CONFIG_FS_ENET_HAS_FCC
+ {
+@@ -1167,10 +1249,17 @@
+ },
+ #endif
+ #ifdef CONFIG_FS_ENET_HAS_FEC
++#ifndef CONFIG_FS_ENET_MPC5121_FEC
+ {
+ .compatible = "fsl,pq1-fec-enet",
+ .data = (void *)&fs_fec_ops,
+ },
++#else
++ {
++ .compatible = "fsl,mpc5121-fec",
++ .data = (void *)&fs_fec_ops,
++ },
++#endif
+ #endif
+ {}
+ };
+@@ -1180,6 +1269,9 @@
+ .match_table = fs_enet_match,
+ .probe = fs_enet_probe,
+ .remove = fs_enet_remove,
++ .suspend = fs_enet_suspend,
++ .resume = fs_enet_resume,
++
+ };
+
+ static int __init fs_init(void)
+diff -Naur linux-2.6.29/drivers/net/fs_enet/Kconfig linux-2.6.29-v2010041601/drivers/net/fs_enet/Kconfig
+--- linux-2.6.29/drivers/net/fs_enet/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/fs_enet/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -1,9 +1,25 @@
+ config FS_ENET
+ tristate "Freescale Ethernet Driver"
+- depends on CPM1 || CPM2
++ depends on CPM1 || CPM2 || FS_ENET_MPC5121_FEC
+ select MII
+ select PHYLIB
+
++config FS_ENET_MPC5121_FEC
++ bool "Freescale MPC512x FEC driver"
++ depends on PPC_MPC512x
++ select FS_ENET
++ select FS_ENET_HAS_FEC
++ select PPC_CPM_NEW_BINDING
++ default n
++
++config FS_ENET_MPC5125_FEC2
++ bool "enable Freescale mpc5125 fec2"
++ depends on PPC_MPC512x && PPC_MPC5125 && FS_ENET_MPC5121_FEC
++ default n
++ help
++ If your enable fec2,usb can't work
++
++
+ config FS_ENET_HAS_SCC
+ bool "Chip has an SCC usable for ethernet"
+ depends on FS_ENET && (CPM1 || CPM2)
+@@ -16,13 +32,15 @@
+
+ config FS_ENET_HAS_FEC
+ bool "Chip has an FEC usable for ethernet"
+- depends on FS_ENET && CPM1
++ depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC)
+ select FS_ENET_MDIO_FEC
+ default y
+
++
+ config FS_ENET_MDIO_FEC
+ tristate "MDIO driver for FEC"
+- depends on FS_ENET && CPM1
++ depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC)
++
+
+ config FS_ENET_MDIO_FCC
+ tristate "MDIO driver for FCC"
+diff -Naur linux-2.6.29/drivers/net/fs_enet/mac-fcc.c linux-2.6.29-v2010041601/drivers/net/fs_enet/mac-fcc.c
+--- linux-2.6.29/drivers/net/fs_enet/mac-fcc.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/fs_enet/mac-fcc.c 2010-04-13 20:23:26.000000000 +0200
+@@ -33,7 +33,6 @@
+ #include <linux/fs.h>
+ #include <linux/platform_device.h>
+ #include <linux/phy.h>
+-#include <linux/of_device.h>
+
+ #include <asm/immap_cpm2.h>
+ #include <asm/mpc8260.h>
+@@ -78,8 +77,16 @@
+ static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op)
+ {
+ const struct fs_platform_info *fpi = fep->fpi;
++ int i;
+
+- return cpm_command(fpi->cp_command, op);
++ W32(cpmp, cp_cpcr, fpi->cp_command | op | CPM_CR_FLG);
++ for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
++ if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
++ return 0;
++
++ printk(KERN_ERR "%s(): Not able to issue CPM command\n",
++ __FUNCTION__);
++ return 1;
+ }
+
+ static int do_pd_setup(struct fs_enet_private *fep)
+@@ -126,12 +133,22 @@
+ #define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB)
+ #define FCC_RX_EVENT (FCC_ENET_RXF)
+ #define FCC_TX_EVENT (FCC_ENET_TXB)
+-#define FCC_ERR_EVENT_MSK (FCC_ENET_TXE)
++#define FCC_ERR_EVENT_MSK (FCC_ENET_TXE | FCC_ENET_BSY)
+
+ static int setup_data(struct net_device *dev)
+ {
+ struct fs_enet_private *fep = netdev_priv(dev);
+
++ struct fs_platform_info *fpi = fep->fpi;
++
++ fpi->cp_command = (fpi->cp_page << 26) |
++ (fpi->cp_block << 21) |
++ (12 << 6);
++
++ fep->fcc.idx = fs_get_fcc_index(fpi->fs_no);
++ if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */
++ return -EINVAL;
++
+ if (do_pd_setup(fep) != 0)
+ return -EINVAL;
+
+@@ -251,6 +268,8 @@
+ fcc_enet_t __iomem *ep = fep->fcc.ep;
+ dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
+ u16 paddrh, paddrm, paddrl;
++ u16 mem_addr;
++
+ const unsigned char *mac;
+ int i;
+
+@@ -398,9 +417,6 @@
+ else
+ C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
+
+- /* Restore multicast and promiscuous settings */
+- set_multicast_list(dev);
+-
+ S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);
+ }
+
+@@ -421,6 +437,16 @@
+ fs_cleanup_bds(dev);
+ }
+
++static void pre_request_irq(struct net_device *dev, int irq)
++{
++ /* nothing */
++}
++
++static void post_free_irq(struct net_device *dev, int irq)
++{
++ /* nothing */
++}
++
+ static void napi_clear_rx_event(struct net_device *dev)
+ {
+ struct fs_enet_private *fep = netdev_priv(dev);
+@@ -530,6 +556,8 @@
+ .set_multicast_list = set_multicast_list,
+ .restart = restart,
+ .stop = stop,
++ .pre_request_irq = pre_request_irq,
++ .post_free_irq = post_free_irq,
+ .napi_clear_rx_event = napi_clear_rx_event,
+ .napi_enable_rx = napi_enable_rx,
+ .napi_disable_rx = napi_disable_rx,
+diff -Naur linux-2.6.29/drivers/net/fs_enet/mac-fec.c linux-2.6.29-v2010041601/drivers/net/fs_enet/mac-fec.c
+--- linux-2.6.29/drivers/net/fs_enet/mac-fec.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/fs_enet/mac-fec.c 2010-04-13 20:23:26.000000000 +0200
+@@ -43,6 +43,9 @@
+ #include <asm/mpc8xx.h>
+ #include <asm/cpm1.h>
+ #endif
++#ifdef CONFIG_FS_ENET_MPC5121_FEC
++#include "fec_mpc5121.h"
++#endif
+
+ #include "fs_enet.h"
+ #include "fec.h"
+@@ -257,13 +260,17 @@
+ u32 addrhi, addrlo;
+
+ struct mii_bus* mii = fep->phydev->bus;
+- struct fec_info* fec_inf = mii->priv;
++// struct fec_info* fec_inf = mii->priv;
+
+ r = whack_reset(fep->fec.fecp);
+ if (r != 0)
+ printk(KERN_ERR DRV_MODULE_NAME
+ ": %s FEC Reset FAILED!\n", dev->name);
+ /*
++ * Reset the mii bus
++ */
++ mii->reset(mii);
++ /*
+ * Set station address.
+ */
+ addrhi = ((u32) dev->dev_addr[0] << 24) |
+@@ -285,7 +292,9 @@
+ * Set maximum receive buffer size.
+ */
+ FW(fecp, r_buff_size, PKT_MAXBLR_SIZE);
++#ifndef CONFIG_FS_ENET_MPC5121_FEC
+ FW(fecp, r_hash, PKT_MAXBUF_SIZE);
++#endif
+
+ /* get physical address */
+ rx_bd_base_phys = fep->ring_mem_addr;
+@@ -299,21 +308,34 @@
+
+ fs_init_bds(dev);
+
++#ifndef CONFIG_FS_ENET_MPC5121_FEC
+ /*
+ * Enable big endian and don't care about SDMA FC.
+ */
+ FW(fecp, fun_code, 0x78000000);
++#else
++ /*
++ * Set DATA_BO and DESC_BO and leave the rest unchanged
++ */
++ FS(fecp, dma_control, 0xc0000000);
++#endif
+
+ /*
+ * Set MII speed.
+ */
+- FW(fecp, mii_speed, fec_inf->mii_speed);
++// FW(fecp, mii_speed, fec_inf->mii_speed);
+
+ /*
+ * Clear any outstanding interrupt.
+ */
+ FW(fecp, ievent, 0xffc0);
++#ifndef CONFIG_FS_ENET_MPC5121_FEC
++#ifndef CONFIG_PPC_MERGE
++ FW(fecp, ivec, (fep->interrupt / 2) << 29);
++#else
+ FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29);
++#endif
++#endif
+
+ /*
+ * adjust to speed (only for DUET & RMII)
+@@ -343,9 +365,17 @@
+ out_be32(&immap->im_cpm.cp_cptr, cptr);
+ }
+ #endif
+-
+-
++#ifdef CONFIG_FS_ENET_MPC5121_FEC
++ FW(fecp, r_cntrl, PKT_MAXBUF_SIZE<<16); /* max frame size */
++#ifdef CONFIG_MPC5125_TWR
++ FS(fecp, r_cntrl, FEC_RCNTRL_RMII_MODE); /* MII enable */
++#else
++ FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
++#endif
++#else
+ FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
++#endif
++
+ /*
+ * adjust to duplex mode
+ */
+@@ -376,7 +406,7 @@
+ const struct fs_platform_info *fpi = fep->fpi;
+ fec_t __iomem *fecp = fep->fec.fecp;
+
+- struct fec_info* feci= fep->phydev->bus->priv;
++// struct fec_info* feci= fep->phydev->bus->priv;
+
+ int i;
+
+@@ -405,10 +435,36 @@
+ FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
+ FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
+ FW(fecp, ievent, FEC_ENET_MII);
+- FW(fecp, mii_speed, feci->mii_speed);
++// FW(fecp, mii_speed, feci->mii_speed);
++ }
++}
++
++#if 0
++static void pre_request_irq(struct net_device *dev, int irq)
++{
++#ifndef CONFIG_PPC_MERGE
++ immap_t *immap = fs_enet_immap;
++ u32 siel;
++
++ /* SIU interrupt */
++ if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) {
++
++ siel = in_be32(&immap->im_siu_conf.sc_siel);
++ if ((irq & 1) == 0)
++ siel |= (0x80000000 >> irq);
++ else
++ siel &= ~(0x80000000 >> (irq & ~1));
++ out_be32(&immap->im_siu_conf.sc_siel, siel);
+ }
++#endif
+ }
+
++static void post_free_irq(struct net_device *dev, int irq)
++{
++ /* nothing */
++}
++#endif
++
+ static void napi_clear_rx_event(struct net_device *dev)
+ {
+ struct fs_enet_private *fep = netdev_priv(dev);
+@@ -501,6 +557,8 @@
+ .set_multicast_list = set_multicast_list,
+ .restart = restart,
+ .stop = stop,
++// .pre_request_irq = pre_request_irq,
++// .post_free_irq = post_free_irq,
+ .napi_clear_rx_event = napi_clear_rx_event,
+ .napi_enable_rx = napi_enable_rx,
+ .napi_disable_rx = napi_disable_rx,
+diff -Naur linux-2.6.29/drivers/net/fs_enet/mac-scc.c linux-2.6.29-v2010041601/drivers/net/fs_enet/mac-scc.c
+--- linux-2.6.29/drivers/net/fs_enet/mac-scc.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/fs_enet/mac-scc.c 2010-04-13 20:23:26.000000000 +0200
+@@ -47,6 +47,7 @@
+ #include "fs_enet.h"
+
+ /*************************************************/
++
+ #if defined(CONFIG_CPM1)
+ /* for a 8xx __raw_xxx's are sufficient */
+ #define __fs_out32(addr, x) __raw_writel(x, addr)
+@@ -61,8 +62,6 @@
+ #define __fs_out16(addr, x) out_be16(addr, x)
+ #define __fs_in32(addr) in_be32(addr)
+ #define __fs_in16(addr) in_be16(addr)
+-#define __fs_out8(addr, x) out_8(addr, x)
+-#define __fs_in8(addr) in_8(addr)
+ #endif
+
+ /* write, read, set bits, clear bits */
+@@ -87,12 +86,21 @@
+ * Delay to wait for SCC reset command to complete (in us)
+ */
+ #define SCC_RESET_DELAY 50
++#define MAX_CR_CMD_LOOPS 10000
+
+ static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op)
+ {
+ const struct fs_platform_info *fpi = fep->fpi;
++ int i;
+
+- return cpm_command(fpi->cp_command, op);
++ W16(cpmp, cp_cpcr, fpi->cp_command | CPM_CR_FLG | (op << 8));
++ for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
++ if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
++ return 0;
++
++ printk(KERN_ERR "%s(): Not able to issue CPM command\n",
++ __FUNCTION__);
++ return 1;
+ }
+
+ static int do_pd_setup(struct fs_enet_private *fep)
+@@ -263,13 +271,8 @@
+
+ /* Initialize function code registers for big-endian.
+ */
+-#ifndef CONFIG_NOT_COHERENT_CACHE
+- W8(ep, sen_genscc.scc_rfcr, SCC_EB | SCC_GBL);
+- W8(ep, sen_genscc.scc_tfcr, SCC_EB | SCC_GBL);
+-#else
+ W8(ep, sen_genscc.scc_rfcr, SCC_EB);
+ W8(ep, sen_genscc.scc_tfcr, SCC_EB);
+-#endif
+
+ /* Set maximum bytes per receive buffer.
+ * This appears to be an Ethernet frame size, not the buffer
+@@ -377,6 +380,30 @@
+ fs_cleanup_bds(dev);
+ }
+
++static void pre_request_irq(struct net_device *dev, int irq)
++{
++#ifndef CONFIG_PPC_MERGE
++ immap_t *immap = fs_enet_immap;
++ u32 siel;
++
++ /* SIU interrupt */
++ if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) {
++
++ siel = in_be32(&immap->im_siu_conf.sc_siel);
++ if ((irq & 1) == 0)
++ siel |= (0x80000000 >> irq);
++ else
++ siel &= ~(0x80000000 >> (irq & ~1));
++ out_be32(&immap->im_siu_conf.sc_siel, siel);
++ }
++#endif
++}
++
++static void post_free_irq(struct net_device *dev, int irq)
++{
++ /* nothing */
++}
++
+ static void napi_clear_rx_event(struct net_device *dev)
+ {
+ struct fs_enet_private *fep = netdev_priv(dev);
+@@ -470,6 +497,8 @@
+ .set_multicast_list = set_multicast_list,
+ .restart = restart,
+ .stop = stop,
++ .pre_request_irq = pre_request_irq,
++ .post_free_irq = post_free_irq,
+ .napi_clear_rx_event = napi_clear_rx_event,
+ .napi_enable_rx = napi_enable_rx,
+ .napi_disable_rx = napi_disable_rx,
+diff -Naur linux-2.6.29/drivers/net/fs_enet/Makefile linux-2.6.29-v2010041601/drivers/net/fs_enet/Makefile
+--- linux-2.6.29/drivers/net/fs_enet/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/fs_enet/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -8,7 +8,12 @@
+ fs_enet-$(CONFIG_FS_ENET_HAS_FEC) += mac-fec.o
+ fs_enet-$(CONFIG_FS_ENET_HAS_FCC) += mac-fcc.o
+
++ifeq ($(CONFIG_PPC_CPM_NEW_BINDING),y)
+ obj-$(CONFIG_FS_ENET_MDIO_FEC) += mii-fec.o
+ obj-$(CONFIG_FS_ENET_MDIO_FCC) += mii-bitbang.o
++else
++fs_enet-$(CONFIG_FS_ENET_MDIO_FEC) += mii-fec.o
++fs_enet-$(CONFIG_FS_ENET_MDIO_FCC) += mii-bitbang.o
++endif
+
+ fs_enet-objs := fs_enet-main.o $(fs_enet-m)
+diff -Naur linux-2.6.29/drivers/net/fs_enet/mii-fec.c linux-2.6.29-v2010041601/drivers/net/fs_enet/mii-fec.c
+--- linux-2.6.29/drivers/net/fs_enet/mii-fec.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/net/fs_enet/mii-fec.c 2010-04-13 20:23:26.000000000 +0200
+@@ -40,6 +40,8 @@
+ #include "fs_enet.h"
+ #include "fec.h"
+
++extern unsigned long ppc_proc_freq;
++
+ /* Make MII read/write commands for the FEC.
+ */
+ #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18))
+@@ -48,14 +50,26 @@
+
+ #define FEC_MII_LOOPS 10000
+
++static int fs_enet_fec_mii_reset(struct mii_bus *bus)
++{
++ struct fec_info *fec = bus->priv;
++
++ setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
++ out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII);
++ out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed);
++ return 0;
++}
++
+ static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
+ {
+ struct fec_info* fec = bus->priv;
+ fec_t __iomem *fecp = fec->fecp;
+ int i, ret = -1;
+
+- if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
+- BUG();
++ if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) {
++ // BUG();
++ fs_enet_fec_mii_reset(bus);
++ }
+
+ /* Add PHY address to register command. */
+ out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_read(location));
+@@ -79,8 +93,10 @@
+ int i;
+
+ /* this must never happen */
+- if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
+- BUG();
++ if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) {
++ // BUG();
++ fs_enet_fec_mii_reset(bus);
++ }
+
+ /* Add PHY address to register command. */
+ out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_write(location, val));
+@@ -96,12 +112,6 @@
+
+ }
+
+-static int fs_enet_fec_mii_reset(struct mii_bus *bus)
+-{
+- /* nothing here - for now */
+- return 0;
+-}
+-
+ static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
+ {
+ const u32 *data;
+@@ -153,8 +163,11 @@
+ goto out_fec;
+
+ fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1;
+-
++#ifdef CONFIG_MPC5125_TWR
++ setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_RMII_MODE);
++#else
+ setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
++#endif
+ setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX |
+ FEC_ECNTRL_ETHER_EN);
+ out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII);
+@@ -211,9 +224,16 @@
+ }
+
+ static struct of_device_id fs_enet_mdio_fec_match[] = {
++#ifdef CONFIG_FS_ENET_FEC
+ {
+ .compatible = "fsl,pq1-fec-mdio",
+ },
++#endif
++#ifdef CONFIG_FS_ENET_MPC5121_FEC
++ {
++ .compatible = "fsl,mpc5121-fec-mdio",
++ },
++#endif
+ {},
+ };
+
+diff -Naur linux-2.6.29/drivers/rtc/Kconfig linux-2.6.29-v2010041601/drivers/rtc/Kconfig
+--- linux-2.6.29/drivers/rtc/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/rtc/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -128,6 +128,12 @@
+
+ if I2C
+
++config RTC_DRV_DS2068A
++ depends on I2C_MPC
++ tristate "SD2068A"
++ help
++ If you say yes here you get support for SD2068A rtc
++
+ config RTC_DRV_DS1307
+ tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00"
+ help
+@@ -735,5 +741,13 @@
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-mv.
++config RTC_DRV_MPC5121
++ tristate "MPC5121 RTC"
++ depends on RTC_CLASS && (PPC_MPC5121||PPC_MPC5125)
++ help
++ If you say yes here you will get support for the
++ built in RTC MPC5121.
+
++ This driver can also be built as a module. If so, the module
++ will be called rtc-mpc5121.
+ endif # RTC_CLASS
+diff -Naur linux-2.6.29/drivers/rtc/Makefile linux-2.6.29-v2010041601/drivers/rtc/Makefile
+--- linux-2.6.29/drivers/rtc/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/rtc/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -49,6 +49,7 @@
+ obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
+ obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
+ obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
++obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
+ obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
+ obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
+ obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
+@@ -76,3 +77,4 @@
+ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
+ obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
+ obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
++obj-$(CONFIG_RTC_DRV_DS2068A) +=rtc-sd2068a.o
+diff -Naur linux-2.6.29/drivers/rtc/rtc-mpc5121.c linux-2.6.29-v2010041601/drivers/rtc/rtc-mpc5121.c
+--- linux-2.6.29/drivers/rtc/rtc-mpc5121.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/rtc/rtc-mpc5121.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,403 @@
++/*
++ * Realtime clock driver for MPC5121
++ *
++ * Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
++ * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * History:
++ *
++ * Based on mpc5200_rtc.c written by Domen Puncer <domen.puncer@telargo.com>
++ * posted to linuxppc-embedded mailing list:
++ * http://patchwork.ozlabs.org/linuxppc-embedded/patch?id=11675
++ * but never commited to any public tree.
++ *
++ * Author: John Rigby <jrigby@freescale.com>
++ * Converted to 5121 rtc driver.
++ *
++ * Make alarms more sane by dealing with lack of second alarm resolution.
++ *
++ * Use actual_time time register for time keeping since it is persistent
++ * and the normal rtc registers are not. Use target_time register as an
++ * offset to linux time.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/rtc.h>
++#include <asm/of_device.h>
++#include <asm/of_platform.h>
++#include <asm/io.h>
++
++struct mpc5121_rtc_regs {
++ u8 set_time; /* RTC + 0x00 */
++ u8 hour_set; /* RTC + 0x01 */
++ u8 minute_set; /* RTC + 0x02 */
++ u8 second_set; /* RTC + 0x03 */
++
++ u8 set_date; /* RTC + 0x04 */
++ u8 month_set; /* RTC + 0x05 */
++ u8 weekday_set; /* RTC + 0x06 */
++ u8 date_set; /* RTC + 0x07 */
++
++ u8 write_sw; /* RTC + 0x08 */
++ u8 sw_set; /* RTC + 0x09 */
++ u16 year_set; /* RTC + 0x0a */
++
++ u8 alm_enable; /* RTC + 0x0c */
++ u8 alm_hour_set; /* RTC + 0x0d */
++ u8 alm_min_set; /* RTC + 0x0e */
++ u8 int_enable; /* RTC + 0x0f */
++
++ u8 reserved1;
++ u8 hour; /* RTC + 0x11 */
++ u8 minute; /* RTC + 0x12 */
++ u8 second; /* RTC + 0x13 */
++
++ u8 month; /* RTC + 0x14 */
++ u8 wday_mday; /* RTC + 0x15 */
++ u16 year; /* RTC + 0x16 */
++
++ u8 int_alm; /* RTC + 0x18 */
++ u8 int_sw; /* RTC + 0x19 */
++ u8 alm_status; /* RTC + 0x1a */
++ u8 sw_minute; /* RTC + 0x1b */
++
++ u8 bus_error_1; /* RTC + 0x1c */
++ u8 int_day; /* RTC + 0x1d */
++ u8 int_min; /* RTC + 0x1e */
++ u8 int_sec; /* RTC + 0x1f */
++
++ /*
++ * target_time:
++ * intended to be used for hibernation but hibernation
++ * does not work on silicon rev 1.5 so use it for non-volatile
++ * storage of offset between the actual_time register and linux time
++ */
++ u32 target_time; /* RTC + 0x20 */
++ /*
++ * actual_time:
++ * readonly time since VBAT_RTC was last connected
++ */
++ u32 actual_time; /* RTC + 0x24 */
++ u32 keep_alive; /* RTC + 0x28 */
++};
++
++struct mpc5121_rtc_data {
++ unsigned irq;
++ unsigned irq_periodic;
++ struct mpc5121_rtc_regs __iomem *regs;
++ struct rtc_device *rtc;
++ struct rtc_wkalrm wkalarm;
++};
++
++/*
++ * Update second/minute/hour registers.
++ *
++ * This is just so alarm will work.
++ */
++static int mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs,
++ struct rtc_time *tm)
++{
++ out_8(®s->second_set, tm->tm_sec);
++ out_8(®s->minute_set, tm->tm_min);
++ out_8(®s->hour_set, tm->tm_hour);
++
++ /* set time sequence */
++ out_8(®s->set_time, 0x1);
++ out_8(®s->set_time, 0x3);
++ out_8(®s->set_time, 0x1);
++ out_8(®s->set_time, 0x0);
++
++ return 0;
++}
++
++static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm)
++{
++ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
++ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
++ unsigned long now;
++
++ /*
++ * linux time is actual_time plus the offset saved in target_time
++ */
++ now = in_be32(®s->actual_time) + in_be32(®s->target_time);
++
++ rtc_time_to_tm(now, tm);
++
++ /*
++ * update second minute hour registers
++ * so alarms will work
++ */
++ mpc5121_rtc_update_smh(regs, tm);
++
++ return 0;
++}
++
++static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
++{
++ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
++ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
++ int ret;
++ unsigned long now;
++
++
++ /*
++ * The actual_time register is read only so we write the offset
++ * between it and linux time to the target_time register.
++ */
++ ret = rtc_tm_to_time(tm, &now);
++ if (ret == 0) {
++ out_be32(®s->target_time, now - in_be32(®s->actual_time));
++ }
++
++ /*
++ * update second minute hour registers
++ * so alarms will work
++ */
++ mpc5121_rtc_update_smh(regs, tm);
++
++ return 0;
++}
++
++static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
++{
++ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
++ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
++
++ *alarm = rtc->wkalarm;
++
++ alarm->pending = in_8(®s->alm_status);
++
++ return 0;
++}
++
++static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
++{
++ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
++ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
++
++ /*
++ * the alarm has no seconds so deal with it
++ */
++ if (alarm->time.tm_sec) {
++ alarm->time.tm_sec = 0;
++ alarm->time.tm_min++;
++ if (alarm->time.tm_min >= 60) {
++ alarm->time.tm_min = 0;
++ alarm->time.tm_hour++;
++ if (alarm->time.tm_hour >= 24) {
++ alarm->time.tm_hour = 0;
++ }
++ }
++ }
++
++ alarm->time.tm_mday = -1;
++ alarm->time.tm_mon = -1;
++ alarm->time.tm_year = -1;
++
++ out_8(®s->alm_min_set, alarm->time.tm_min);
++ out_8(®s->alm_hour_set, alarm->time.tm_hour);
++
++ out_8(®s->alm_enable, alarm->enabled);
++
++ rtc->wkalarm = *alarm;
++ return 0;
++}
++
++static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
++{
++ struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
++ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
++
++ if (in_8(®s->int_alm)) {
++ /* acknowledge and clear status */
++ out_8(®s->int_alm, 1);
++ out_8(®s->alm_status, 1);
++
++ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
++ return IRQ_HANDLED;
++ }
++
++ return IRQ_NONE;
++}
++
++static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
++{
++ struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
++ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
++
++ if (in_8(®s->int_sec) && (in_8(®s->int_enable) & 0x1)) {
++ /* acknowledge */
++ out_8(®s->int_sec, 1);
++
++ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF);
++ return IRQ_HANDLED;
++ }
++
++ return IRQ_NONE;
++}
++
++static int mpc5121_rtc_ioctl(struct device *dev, unsigned int cmd,
++ unsigned long arg)
++{
++ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
++ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
++
++ switch (cmd) {
++ /* alarm interrupt */
++ case RTC_AIE_ON:
++ out_8(®s->alm_enable, 1);
++ rtc->wkalarm.enabled = 1;
++ break;
++ case RTC_AIE_OFF:
++ out_8(®s->alm_enable, 0);
++ rtc->wkalarm.enabled = 0;
++ break;
++
++ /* update interrupt */
++ case RTC_UIE_ON:
++ out_8(®s->int_enable,
++ (in_8(®s->int_enable) & ~0x8) | 0x1);
++ break;
++ case RTC_UIE_OFF:
++ out_8(®s->int_enable, in_8(®s->int_enable) & ~0x1);
++ break;
++
++ /* no periodic interrupts */
++ case RTC_IRQP_READ:
++ case RTC_IRQP_SET:
++ return -ENOTTY;
++
++ default:
++ return -ENOIOCTLCMD;
++ }
++ return 0;
++}
++
++static const struct rtc_class_ops mpc5121_rtc_ops = {
++ .read_time = mpc5121_rtc_read_time,
++ .set_time = mpc5121_rtc_set_time,
++ .read_alarm = mpc5121_rtc_read_alarm,
++ .set_alarm = mpc5121_rtc_set_alarm,
++ .ioctl = mpc5121_rtc_ioctl,
++};
++
++static int __devinit mpc5121_rtc_probe(struct of_device *op,
++ const struct of_device_id *match)
++{
++ struct mpc5121_rtc_data *rtc;
++ int err = 0;
++
++ rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
++ if (!rtc) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ rtc->regs = of_iomap(op->node, 0);
++
++ if (!rtc->regs) {
++ printk(KERN_ERR "%s: couldn't map io space\n", __func__);
++ err = -ENOSYS;
++ goto out_free;
++ }
++
++ device_init_wakeup(&op->dev, 1);
++
++ rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev,
++ &mpc5121_rtc_ops, THIS_MODULE);
++ if (IS_ERR(rtc->rtc)) {
++ err = PTR_ERR(rtc->rtc);
++ goto out_unmap;
++ }
++
++ dev_set_drvdata(&op->dev, rtc);
++
++ rtc->irq = irq_of_parse_and_map(op->node, 1);
++ if ((err =
++ request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED,
++ "mpc5121-rtc", &op->dev))) {
++ printk(KERN_ERR "%s: could not request irq: %i\n", __func__,
++ rtc->irq);
++ goto out_dispose;
++ }
++
++ rtc->irq_periodic = irq_of_parse_and_map(op->node, 0);
++ if ((err =
++ request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd,
++ IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev))) {
++ printk(KERN_ERR "%s: could not request irq: %i\n", __func__,
++ rtc->irq_periodic);
++ goto out_dispose2;
++ }
++
++ goto out;
++
++ out_dispose2:
++ irq_dispose_mapping(rtc->irq_periodic);
++ free_irq(rtc->irq, &op->dev);
++ out_dispose:
++ irq_dispose_mapping(rtc->irq);
++ out_unmap:
++ iounmap(rtc->regs);
++ out_free:
++ kfree(rtc);
++ out:
++ return err;
++}
++
++static int __devexit mpc5121_rtc_remove(struct of_device *op)
++{
++ struct mpc5121_rtc_data *rtc = dev_get_drvdata(&op->dev);
++ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
++
++ /* disable interrupt, so there are no nasty surprises */
++ out_8(®s->alm_enable, 0);
++ out_8(®s->int_enable, in_8(®s->int_enable) & ~0x1);
++
++ rtc_device_unregister(rtc->rtc);
++ iounmap(rtc->regs);
++ free_irq(rtc->irq, &op->dev);
++ free_irq(rtc->irq_periodic, &op->dev);
++ irq_dispose_mapping(rtc->irq);
++ irq_dispose_mapping(rtc->irq_periodic);
++ kfree(rtc);
++ dev_set_drvdata(&op->dev, NULL);
++
++ return 0;
++}
++
++static struct of_device_id mpc5121_rtc_match[] = {
++ {.compatible = "fsl,mpc5121-rtc",},
++ {},
++};
++
++static struct of_platform_driver mpc5121_rtc_driver = {
++ .owner = THIS_MODULE,
++ .name = "mpc5121-rtc",
++ .match_table = mpc5121_rtc_match,
++ .probe = mpc5121_rtc_probe,
++ .remove = mpc5121_rtc_remove,
++};
++
++static int __init mpc5121_rtc_init(void)
++{
++ return of_register_platform_driver(&mpc5121_rtc_driver);
++}
++
++static void __exit mpc5121_rtc_exit(void)
++{
++ of_unregister_platform_driver(&mpc5121_rtc_driver);
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("John Rigby <jrigby@freescale.com>");
++
++module_init(mpc5121_rtc_init);
++module_exit(mpc5121_rtc_exit);
+diff -Naur linux-2.6.29/drivers/rtc/rtc-sd2068a.c linux-2.6.29-v2010041601/drivers/rtc/rtc-sd2068a.c
+--- linux-2.6.29/drivers/rtc/rtc-sd2068a.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/rtc/rtc-sd2068a.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,674 @@
++/*
++ * rtc-ds1307.c - RTC driver for some mostly-compatible I2C chips.
++ *
++ * Copyright (C) 2005 James Chapman (ds1337 core)
++ * Copyright (C) 2006 David Brownell
++ *
++ * This program is free software; you can 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/slab.h>
++#include <linux/i2c.h>
++#include <linux/string.h>
++#include <linux/rtc.h>
++#include <linux/bcd.h>
++
++
++
++/* We can't determine type by probing, but if we expect pre-Linux code
++ * to have set the chip up as a clock (turning on the oscillator and
++ * setting the date and time), Linux can ignore the non-clock features.
++ * That's a natural job for a factory or repair bench.
++ *
++ * This is currently a simple no-alarms driver. If your board has the
++ * alarm irq wired up on a ds1337 or ds1339, and you want to use that,
++ * then look at the rtc-rs5c372 driver for code to steal...
++ */
++
++#define BCD2BIN(val) bcd2bin(val)
++#define BIN2BCD(val) bin2bcd(val)
++static int sd2068_uie_on_off(struct device *dev,unsigned char enable);
++#define ENABLE_ALARM_INT 0
++#if 1
++#define RTC_DS1307_DEBUG()
++#else
++#define RTC_DS1307_DEBUG() printk("%s() line:%d\n",__FUNCTION__,__LINE__)
++#endif
++/* RTC registers don't differ much, except for the century flag */
++enum{
++SD2608_REG_SEC=0x00,
++SD2608_REG_MIN,
++SD2608_REG_HOUR,
++SD2608_REG_DAY_OF_WEEK,
++SD2608_REG_DAY_OF_MONTH,
++SD2608_REG_MONTH,
++SD2608_REG_YEAR
++};
++#define SD2068_HOUR_12_24_CONTROL 0x80
++#define SD2068_CTR2_WRTC1 0x80
++#define SD2068_CTR1_WRTC2_WRTC3 0x84
++
++/* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
++ * start at 7, and they differ a LOT. Only control and status matter for
++ * basic RTC date and time functionality; be careful using them.
++ */
++
++
++
++struct sd2068_struct {
++ u8 reg_addr;
++ bool has_nvram;
++ u8 regs[8];
++ u8 msb_buf[8];
++ u8 ctrl_reg[4];
++ //enum ds_type type;
++ struct i2c_msg msg[4];
++ struct i2c_client *client;
++ struct i2c_client dev;
++ struct rtc_device *rtc;
++};
++/*
++
++struct chip_desc {
++ char name[9];
++ unsigned nvram56:1;
++ unsigned alarm:1;
++ enum ds_type type;
++};
++
++static const struct chip_desc chips[] = { {
++ .name = "ds1307",
++ .type = ds_1307,
++ .nvram56 = 1,
++}, {
++ .name = "ds1337",
++ .type = ds_1337,
++ .alarm = 1,
++}, {
++ .name = "ds1338",
++ .type = ds_1338,
++ .nvram56 = 1,
++}, {
++ .name = "ds1339",
++ .type = ds_1339,
++ .alarm = 1,
++}, {
++ .name = "ds1340",
++ .type = ds_1340,
++}, {
++ .name = "m41t00",
++ .type = m41t00,
++}, };
++
++static inline const struct chip_desc *find_chip(const char *s)
++{
++ unsigned i;
++
++ for (i = 0; i < ARRAY_SIZE(chips); i++)
++ if (strnicmp(s, chips[i].name, sizeof chips[i].name) == 0)
++ return &chips[i];
++ return NULL;
++}
++*/
++static int sd2068_get_time(struct device *dev, struct rtc_time *t)
++{
++ struct sd2068_struct *sd2068 = dev_get_drvdata(dev);
++ unsigned char tmp;
++
++ /* read the RTC date and time registers all at once */
++ sd2068->msg[1].flags = I2C_M_RD;
++ sd2068->msg[1].len = 7;
++
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ sd2068->msg, 2);
++ if (tmp != 2) {
++ dev_err(dev, "%s error %d\n", "read", tmp);
++ return -EIO;
++ }
++/*
++ printk("%s:%02x %02x %02x %02x %02x %02x %02x\n",
++ "read",
++ sd2068->regs[0], sd2068->regs[1],
++ sd2068->regs[2], sd2068->regs[3],
++ sd2068->regs[4], sd2068->regs[5],
++ sd2068->regs[6]);
++*/
++ t->tm_sec = BCD2BIN(sd2068->regs[SD2608_REG_SEC] & 0x7f);
++ t->tm_min = BCD2BIN(sd2068->regs[SD2608_REG_MIN] & 0x7f);
++ tmp = sd2068->regs[SD2608_REG_HOUR] & 0x3f;
++ t->tm_hour =BCD2BIN (tmp&(~SD2068_HOUR_12_24_CONTROL));
++ t->tm_wday = BCD2BIN(sd2068->regs[SD2608_REG_DAY_OF_WEEK] & 0x07) ;
++ t->tm_mday =BCD2BIN (sd2068->regs[SD2608_REG_DAY_OF_MONTH] & 0x3f);
++ tmp = sd2068->regs[SD2608_REG_MONTH] & 0x1f;
++ t->tm_mon =BCD2BIN (tmp);
++
++
++ t->tm_year = BCD2BIN(sd2068->regs[SD2608_REG_YEAR])+2000-1900;
++#if 0
++ printk(KERN_ERR "%s:secs=%d, mins=%d, "
++ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
++ "read", t->tm_sec, t->tm_min,
++ t->tm_hour, t->tm_mday,
++ t->tm_mon, t->tm_year, t->tm_wday);
++#endif
++ /* initial clock setting can be undefined */
++ return rtc_valid_tm(t);
++}
++
++static int sd2068_set_time(struct device *dev, struct rtc_time *t)
++{
++ struct sd2068_struct *sd2068 = dev_get_drvdata(dev);
++ int result;
++ int tmp;
++ u8 *buf = sd2068->regs;
++#if 0
++ printk(KERN_ERR"%s:secs=%d, mins=%d, "
++ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
++ "write", t->tm_sec, t->tm_min,
++ t->tm_hour, t->tm_mday,
++ t->tm_mon, t->tm_year, t->tm_wday);
++#endif
++ *buf++ = 0; /* first register addr */
++ buf[SD2608_REG_SEC] = BIN2BCD(t->tm_sec);
++ buf[SD2608_REG_MIN] =BIN2BCD (t->tm_min);
++ buf[SD2608_REG_HOUR] = BIN2BCD(t->tm_hour)|SD2068_HOUR_12_24_CONTROL;
++ buf[SD2608_REG_DAY_OF_WEEK] = BIN2BCD(t->tm_wday);
++ buf[SD2608_REG_DAY_OF_MONTH] = BIN2BCD(t->tm_mday);
++ buf[SD2608_REG_MONTH] = BIN2BCD(t->tm_mon );
++
++ /* assume 20YY not 19YY */
++ if((t->tm_year+1900>2100)||(t->tm_year+1900<2000))
++ {
++ printk(KERN_ERR"rtc range is from 2000 to 2100.\n");
++ return -1;
++ }
++ tmp = t->tm_year+1900-2000;
++ buf[SD2608_REG_YEAR] =BIN2BCD (tmp);
++
++
++ sd2068->msg[1].flags = 0;
++ sd2068->msg[1].len = 8;
++
++ dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
++ "write", buf[0], buf[1], buf[2], buf[3],
++ buf[4], buf[5], buf[6]);
++ sd2068_uie_on_off(dev,1);
++ result = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[1], 1);
++ sd2068_uie_on_off(dev,0);
++ if (result != 1) {
++ dev_err(dev, "%s error %d\n", "write", tmp);
++ return -EIO;
++ }
++ return 0;
++}
++
++/*********
++0:disable
++1:enable
++*************/
++static int sd2068_uie_on_off(struct device *dev,unsigned char enable)
++{
++ struct sd2068_struct *sd2068 = dev_get_drvdata(dev);
++ int tmp;
++ u8 buf[2];
++ sd2068->msg[2].flags = 0;
++ sd2068->msg[2].len = 1;
++ sd2068->msg[2].buf[0]=0x0f;
++
++ sd2068->msg[3].flags = I2C_M_RD;
++ sd2068->msg[3].len = 2;
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[2], 2);
++ if(tmp!=2)
++ {
++ printk(KERN_ERR"%s() %d read failed.\n",__FUNCTION__,__LINE__);
++ return -1;
++ }
++ buf[0]=sd2068->msg[3].buf[0];
++ buf[1]=sd2068->msg[3].buf[1];
++ //printk("buf[0]=0x%02x buf[1]=0x%02x\n",buf[0],buf[1]);
++ sd2068->msg[3].flags = 0;
++ sd2068->msg[3].len = 2;
++ if(enable)
++ {
++ sd2068->msg[3].buf[0]=0x10;
++ sd2068->msg[3].buf[1]=buf[1]|SD2068_CTR2_WRTC1;
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[3], 1);
++ RTC_DS1307_DEBUG();
++ if(tmp!=1)
++ {
++ goto failed;
++ }
++ sd2068->msg[3].buf[0]=0x0f;
++ sd2068->msg[3].buf[1]=buf[0]|SD2068_CTR1_WRTC2_WRTC3;
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[3], 1);
++
++ if(tmp!=1)
++ {
++ goto failed;
++ }
++ RTC_DS1307_DEBUG();
++ }
++ else
++ {
++ sd2068->msg[3].buf[0]=0x0f;
++ sd2068->msg[3].buf[1]=buf[0]&(~SD2068_CTR1_WRTC2_WRTC3);
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[3], 1);
++ RTC_DS1307_DEBUG();
++ if(tmp!=1)
++ {
++ goto failed;
++ }
++ RTC_DS1307_DEBUG();
++ sd2068->msg[3].buf[0]=0x10;
++ sd2068->msg[3].buf[1]=buf[1]&(~SD2068_CTR2_WRTC1);
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[3], 1);
++ if(tmp!=1)
++ {
++ goto failed;
++ }
++ RTC_DS1307_DEBUG();
++ }
++
++ return 0;
++failed:
++ printk(KERN_ERR"%s() %d read failed.\n",__FUNCTION__,__LINE__);
++ return -1;
++
++
++}
++
++static int sd2068_rtc_ioctl(struct device *dev, unsigned int cmd,
++ unsigned long arg)
++{
++ struct sd2068_struct *sd2068 = dev_get_drvdata(dev);
++ //struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
++ RTC_DS1307_DEBUG();
++ //printk("cmd:0x%08x\n",cmd);
++ switch (cmd) {
++ /* alarm interrupt */
++ case RTC_AIE_ON:
++ //out_8(®s->alm_enable, 1);
++ //rtc->wkalarm.enabled = 1;
++ break;
++ case RTC_AIE_OFF:
++ //out_8(®s->alm_enable, 0);
++ //rtc->wkalarm.enabled = 0;
++ break;
++
++ /* update interrupt */
++
++ case RTC_UIE_ON:
++ //RTC_DS1307_DEBUG();
++ return -ENOTTY;
++ case RTC_UIE_OFF:
++ //out_8(®s->int_enable, in_8(®s->int_enable) & ~0x1);
++ //RTC_DS1307_DEBUG();
++ return -ENOTTY;
++ case RTC_RD_TIME:
++ RTC_DS1307_DEBUG();
++ {
++ struct rtc_time rtc_tm;
++
++ memset(&rtc_tm, 0, sizeof (struct rtc_time));
++ sd2068_get_time(dev,&rtc_tm);
++ if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
++ return -EFAULT;
++ return 0;
++ }
++ break;
++ case RTC_SET_TIME:
++ RTC_DS1307_DEBUG();
++ {
++ struct rtc_time rtc_tm;
++ unsigned char mon, day, hrs, min, sec, leap_yr;
++ unsigned int yrs;
++
++ if (!capable(CAP_SYS_TIME))
++ return -EPERM;
++
++ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
++ return -EFAULT;
++#if 0
++ printk( "%s:secs=%d, mins=%d, "
++ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
++ "write",rtc_tm.tm_sec, rtc_tm.tm_min,
++ rtc_tm.tm_hour,rtc_tm.tm_mday,
++ rtc_tm.tm_mon, rtc_tm.tm_year, rtc_tm.tm_wday);
++#endif
++ sd2068_set_time(dev,&rtc_tm);
++
++ return 0;
++ }
++ break;
++
++ /* no periodic interrupts */
++ case RTC_IRQP_READ:
++ case RTC_IRQP_SET:
++ return -ENOTTY;
++
++ default:
++ return -ENOIOCTLCMD;
++ }
++ return 0;
++}
++
++static const struct rtc_class_ops sd2068_rtc_ops = {
++ .read_time = sd2068_get_time,
++ .set_time = sd2068_set_time,
++ .ioctl = sd2068_rtc_ioctl,
++};
++
++/*----------------------------------------------------------------------*/
++
++#define NVRAM_SIZE 56
++
++/*----------------------------------------------------------------------*/
++
++static struct i2c_driver sd2608_driver;
++#if ENABLE_ALARM_INT
++static int sd2068_set_alarm(struct device *dev,unsigned int irq)
++{
++ struct sd2068_struct *sd2068 = dev_get_drvdata(dev);
++ //int result;
++ int tmp;
++ sd2068->msg[2].flags = 0;
++ sd2068->msg[2].len = 1;
++ sd2068->msg[2].buf[0]=0x0e;
++
++ sd2068->msg[3].flags = I2C_M_RD;
++ sd2068->msg[3].len = 1;
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[2], 2);
++ if(tmp!=2)
++ {
++ printk(KERN_ERR"%s() %d read failed.\n",__FUNCTION__,__LINE__);
++ return -1;
++ }
++ tmp=sd2068->msg[3].buf[0];
++ tmp|=irq;
++ tmp&=0x7f;
++ //tmp|=0x40;
++ //tmp=(tmp)?(tmp|0x80):tmp;
++ sd2068_uie_on_off(dev,1);
++ sd2068->msg[2].flags = 0;
++ sd2068->msg[2].len = 2;
++ sd2068->msg[2].buf[0]=0x0e;
++ sd2068->msg[2].buf[1]=tmp;
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[2], 1);
++ if(tmp!=1)
++ {
++ printk(KERN_ERR"%s() %d read failed.\n",__FUNCTION__,__LINE__);
++ goto setfailed;
++ }
++
++ sd2068->msg[2].flags = 0;
++ sd2068->msg[2].len = 2;
++ sd2068->msg[2].buf[0]=0x07;
++ sd2068->msg[2].buf[1]=0x20;
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[2], 1);
++ if(tmp!=1)
++ {
++ printk(KERN_ERR"%s() %d read failed.\n",__FUNCTION__,__LINE__);
++ goto setfailed;
++ }
++ sd2068_uie_on_off(dev,0);
++
++ sd2068->msg[2].flags = 0;
++ sd2068->msg[2].len = 1;
++ sd2068->msg[2].buf[0]=0x0e;
++
++ sd2068->msg[3].flags = I2C_M_RD;
++ sd2068->msg[3].len = 1;
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[2], 2);
++ if(tmp!=2)
++ {
++ printk(KERN_ERR"%s() %d read failed.\n",__FUNCTION__,__LINE__);
++ goto setfailed;
++ }
++ printk(KERN_ERR"%s() %d read [0x0e]=0x%02x\n",__FUNCTION__,__LINE__,sd2068->msg[3].buf[0]);
++
++ sd2068->msg[2].flags = 0;
++ sd2068->msg[2].len = 1;
++ sd2068->msg[2].buf[0]=0x07;
++
++ sd2068->msg[3].flags = I2C_M_RD;
++ sd2068->msg[3].len = 1;
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[2], 2);
++ if(tmp!=2)
++ {
++ printk(KERN_ERR"%s() %d read failed.\n",__FUNCTION__,__LINE__);
++ goto setfailed;
++ }
++ printk(KERN_ERR"%s() %d read [0x07]=0x%02x\n",__FUNCTION__,__LINE__,sd2068->msg[3].buf[0]);
++ return 0;
++setfailed:
++ sd2068_uie_on_off(dev,0);
++ return -1;
++}
++
++static int sd2068_set_alarm_mode(struct device *dev,unsigned int mode)
++{
++ struct sd2068_struct *sd2068 = dev_get_drvdata(dev);
++ //int result;
++ int tmp;
++ sd2068->msg[2].flags = 0;
++ sd2068->msg[2].len = 1;
++ sd2068->msg[2].buf[0]=0x10;
++
++ sd2068->msg[3].flags = I2C_M_RD;
++ sd2068->msg[3].len = 1;
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[2], 2);
++ if(tmp!=2)
++ {
++ printk(KERN_ERR"%s() %d read failed.\n",__FUNCTION__,__LINE__);
++ return -1;
++ }
++ tmp=sd2068->msg[3].buf[0];
++ tmp&=0xcf;
++ tmp|=mode<<4;
++ tmp|=0x40;
++ tmp|=0x02;
++ sd2068_uie_on_off(dev,1);
++ sd2068->msg[2].flags = 0;
++ sd2068->msg[2].len = 2;
++ sd2068->msg[2].buf[0]=0x10;
++ sd2068->msg[2].buf[1]=tmp;
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[2], 1);
++ if(tmp!=1)
++ {
++ printk(KERN_ERR"%s() %d read failed.\n",__FUNCTION__,__LINE__);
++ goto setfailed;
++ }
++
++ sd2068_uie_on_off(dev,0);
++ sd2068->msg[2].flags = 0;
++ sd2068->msg[2].len = 1;
++ sd2068->msg[2].buf[0]=0x10;
++
++ sd2068->msg[3].flags = I2C_M_RD;
++ sd2068->msg[3].len = 1;
++ tmp = i2c_transfer(to_i2c_adapter(sd2068->client->dev.parent),
++ &sd2068->msg[2], 2);
++ if(tmp!=2)
++ {
++ printk(KERN_ERR"%s() %d read failed.\n",__FUNCTION__,__LINE__);
++ goto setfailed;
++ }
++ printk(KERN_ERR"%s() %d read [0x10]=0x%02x\n",__FUNCTION__,__LINE__,sd2068->msg[3].buf[0]);
++ return 0;
++setfailed:
++ sd2068_uie_on_off(dev,0);
++ return -1;
++}
++#endif
++
++static int __devinit sd2068_probe(struct i2c_client *client)
++{
++ struct sd2068_struct *sd2068;
++ int err = -ENODEV;
++ int tmp;
++
++ //const struct chip_desc *chip;
++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
++ RTC_DS1307_DEBUG();
++/*
++ chip = find_chip(client->name);
++ if (!chip) {
++ dev_err(&client->dev, "unknown chip type '%s'\n",
++ client->name);
++ return -ENODEV;
++ }
++*/
++ /*printk("chip name:%s \n",client->name);*/
++ RTC_DS1307_DEBUG();
++#if 0
++ if (!i2c_check_functionality(adapter,
++ I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
++ return -EIO;
++#else
++ if (!i2c_check_functionality(adapter,I2C_FUNC_I2C))
++ return -EIO;
++#endif
++ RTC_DS1307_DEBUG();
++
++ if (!(sd2068 = kzalloc(sizeof(struct sd2068_struct), GFP_KERNEL)))
++ return -ENOMEM;
++
++ /*printk("client->addr:%d\n",client->addr);*/
++ sd2068->reg_addr=0;
++ sd2068->client = client;
++ i2c_set_clientdata(client, sd2068);
++
++ sd2068->msg[0].addr = client->addr;
++ sd2068->msg[0].flags = 0;
++ sd2068->msg[0].len = 1;
++ sd2068->msg[0].buf = &sd2068->reg_addr;
++
++ sd2068->msg[2].addr = client->addr;
++ sd2068->msg[2].flags = 0;
++ sd2068->msg[2].len = 1;
++ sd2068->msg[2].buf = sd2068->ctrl_reg;
++ sd2068->ctrl_reg[0]=0x0f;
++
++
++ sd2068->msg[3].addr = client->addr;
++ sd2068->msg[3].flags = I2C_M_RD;
++ sd2068->msg[3].len = 2;
++ sd2068->msg[3].buf = sd2068->msb_buf;
++
++ //sd2068->msb_buf[0]=0x0f;
++ //sd2068->msb_buf[1]=0;
++
++
++ sd2068->msg[1].addr = client->addr;
++ sd2068->msg[1].flags = I2C_M_RD;
++ sd2068->msg[1].len = 7;
++ sd2068->msg[1].buf = sd2068->regs;
++
++
++#if ENABLE_ALARM_INT
++ sd2068_set_alarm_mode(&client->dev,1);
++ sd2068_set_alarm(&client->dev,1);
++#endif
++
++
++
++
++
++read_rtc:
++ /* read RTC registers */
++ RTC_DS1307_DEBUG();
++ tmp = i2c_transfer(adapter, sd2068->msg, 2);
++ if (tmp != 2) {
++ pr_debug("read error %d\n", tmp);
++ err = -EIO;
++ goto exit_free;
++ }
++
++
++ RTC_DS1307_DEBUG();
++ sd2068->rtc = rtc_device_register(client->name, &client->dev,
++ &sd2068_rtc_ops, THIS_MODULE);
++
++ if (IS_ERR(sd2068->rtc)) {
++ err = PTR_ERR(sd2068->rtc);
++ dev_err(&client->dev,
++ "unable to register the class device\n");
++ goto exit_free;
++ }
++
++ RTC_DS1307_DEBUG();
++ printk("Register rtc:%s \n",client->name);
++
++
++ return 0;
++exit_bad:
++ printk("%s: %02x %02x %02x %02x %02x %02x %02x %02x\n",
++ "bogus register",
++ sd2068->regs[0], sd2068->regs[1],
++ sd2068->regs[2], sd2068->regs[3],
++ sd2068->regs[4], sd2068->regs[5],
++ sd2068->regs[6],sd2068->regs[7]);
++
++exit_free:
++ kfree(sd2068);
++ return err;
++}
++
++static int __devexit sd2068_remove(struct i2c_client *client)
++{
++ struct sd2068_struct *sd2068 = i2c_get_clientdata(client);
++
++
++
++ rtc_device_unregister(sd2068->rtc);
++ kfree(sd2068);
++ return 0;
++}
++static const struct i2c_device_id ds2068_id[] = {
++ { "sd2068", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, ds2068_id);
++
++static struct i2c_driver sd2068_driver = {
++ .driver = {
++ .name = "rtc-sd2068",
++ .owner = THIS_MODULE,
++ },
++ .probe = sd2068_probe,
++ .remove = __devexit_p(sd2068_remove),
++ .id_table = ds2068_id,
++};
++
++static int __init sd2068_init(void)
++{
++ RTC_DS1307_DEBUG();
++ return i2c_add_driver(&sd2068_driver);
++}
++module_init(sd2068_init);
++
++static void __exit ds1307_exit(void)
++{
++ i2c_del_driver(&sd2068_driver);
++}
++module_exit(ds1307_exit);
++
++MODULE_DESCRIPTION("RTC driver for DS1307 and similar chips");
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.29/drivers/serial/mpc52xx_uart.c linux-2.6.29-v2010041601/drivers/serial/mpc52xx_uart.c
+--- linux-2.6.29/drivers/serial/mpc52xx_uart.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/serial/mpc52xx_uart.c 2010-04-13 20:23:26.000000000 +0200
+@@ -522,7 +522,7 @@
+
+ /* Request IRQ */
+ ret = request_irq(port->irq, mpc52xx_uart_int,
+- IRQF_DISABLED | IRQF_SAMPLE_RANDOM | IRQF_SHARED,
++ IRQF_SAMPLE_RANDOM | IRQF_SHARED,
+ "mpc52xx_psc_uart", port);
+ if (ret)
+ return ret;
+@@ -533,6 +533,14 @@
+
+ out_be32(&psc->sicr, 0); /* UART mode DCD ignored */
+
++ /* set prescaler */
++#ifdef CONFIG_PPC_MPC5125
++ out_8(&PSC(port)->mpc52xx_psc_clock_select, 0xdd);
++#else
++ out_be16(&PSC(port)->mpc52xx_psc_clock_select, 0xdd00);
++#endif
++
++
+ psc_ops->fifo_init(port);
+
+ out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
+@@ -633,9 +641,14 @@
+ out_8(&psc->command, MPC52xx_PSC_RST_TX);
+
+ /* Send new mode settings */
++#ifdef CONFIG_PPC_MPC5125
++ out_8(&psc->mr1, mr1);
++ out_8(&psc->mr2, mr2);
++#else
+ out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+ out_8(&psc->mode, mr1);
+ out_8(&psc->mode, mr2);
++#endif
+ out_8(&psc->ctur, ctr >> 8);
+ out_8(&psc->ctlr, ctr & 0xff);
+
+@@ -909,8 +922,12 @@
+ pr_debug("mpc52xx_console_get_options(port=%p)\n", port);
+
+ /* Read the mode registers */
++#ifdef CONFIG_PPC_MPC5125
++ mr1 = in_8(&psc->mr1);
++#else
+ out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+ mr1 = in_8(&psc->mode);
++#endif
+
+ /* CT{U,L}R are write-only ! */
+ *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
+@@ -1100,6 +1117,12 @@
+ #ifdef CONFIG_PPC_MPC512x
+ { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, },
+ #endif
++#ifdef CONFIG_PPC_MPC5125
++ {.type = "serial",
++ .compatible = "fsl,mpc5125-psc-uart",
++ .data = &mpc512x_psc_ops},
++#endif
++
+ {},
+ };
+
+diff -Naur linux-2.6.29/drivers/staging/rt2870/Kconfig linux-2.6.29-v2010041601/drivers/staging/rt2870/Kconfig
+--- linux-2.6.29/drivers/staging/rt2870/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/staging/rt2870/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -1,6 +1,19 @@
+ config RT2870
+ tristate "Ralink 2870 wireless support"
+- depends on USB && X86 && WLAN_80211
++ depends on USB && WLAN_80211
+ ---help---
+ This is an experimental driver for the Ralink 2870 wireless chip.
+
++config RT2870_DEBUG
++ bool "Enable Ralink 2870 wireless debugging messages"
++ depends on RT2870
++ default n
++ help
++ debugging messages
++
++config RT2870_BIG_ENDIAN
++ bool "Enable Ralink 2870 wireless BIG-ENDIAN"
++ depends on RT2870
++ default n
++ help
++ BIG-ENDIAN
+diff -Naur linux-2.6.29/drivers/staging/rt2870/Makefile linux-2.6.29-v2010041601/drivers/staging/rt2870/Makefile
+--- linux-2.6.29/drivers/staging/rt2870/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/staging/rt2870/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -4,11 +4,18 @@
+ EXTRA_CFLAGS += -DLINUX -DAGGREGATION_SUPPORT -DPIGGYBACK_SUPPORT -DWMM_SUPPORT
+ EXTRA_CFLAGS += -DRT2870
+ EXTRA_CFLAGS += -DCONFIG_STA_SUPPORT
+-EXTRA_CFLAGS += -DDBG
+ EXTRA_CFLAGS += -DDOT11_N_SUPPORT
+ EXTRA_CFLAGS += -DWPA_SUPPLICANT_SUPPORT
+ EXTRA_CFLAGS += -DNATIVE_WPA_SUPPLICANT_SUPPORT
+
++ifeq ($(CONFIG_RT2870_BIG_ENDIAN),y)
++EXTRA_CFLAGS += -DRT_BIG_ENDIAN
++endif
++
++ifeq ($(CONFIG_RT2870_DEBUG),y)
++EXTRA_CFLAGS += -DDBG
++endif
++
+ rt2870sta-objs := \
+ common/md5.o \
+ common/mlme.o \
+diff -Naur linux-2.6.29/drivers/usb/core/message.c linux-2.6.29-v2010041601/drivers/usb/core/message.c
+--- linux-2.6.29/drivers/usb/core/message.c 2011-02-27 13:59:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/usb/core/message.c 2010-04-13 20:23:26.000000000 +0200
+@@ -14,6 +14,8 @@
+ #include <linux/scatterlist.h>
+ #include <linux/usb/quirks.h>
+ #include <asm/byteorder.h>
++#include <asm/mpc5121_struct.h>
++
+
+ #include "hcd.h" /* for usbcore internals */
+ #include "usb.h"
+@@ -45,7 +47,9 @@
+ struct api_context ctx;
+ unsigned long expire;
+ int retval;
+-
++#ifndef CONFIG_MPC5125_TWR
++ mpc5121_usb_ide_dma_lock();
++#endif
+ init_completion(&ctx.done);
+ urb->context = &ctx;
+ urb->actual_length = 0;
+@@ -72,6 +76,9 @@
+ *actual_length = urb->actual_length;
+
+ usb_free_urb(urb);
++#ifndef CONFIG_MPC5125_TWR
++ mpc5121_usb_ide_dma_unlock();
++#endif
+ return retval;
+ }
+
+diff -Naur linux-2.6.29/drivers/usb/gadget/fsl_usb2_udc.c linux-2.6.29-v2010041601/drivers/usb/gadget/fsl_usb2_udc.c
+--- linux-2.6.29/drivers/usb/gadget/fsl_usb2_udc.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/usb/gadget/fsl_usb2_udc.c 2010-04-13 20:23:26.000000000 +0200
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2004-2007 Freescale Semicondutor, Inc. All rights reserved.
++ * Copyright (C) 2004-2008 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Author: Li Yang <leoli@freescale.com>
+ * Jiang Bo <tanya.jiang@freescale.com>
+@@ -16,6 +16,7 @@
+ * option) any later version.
+ */
+
++#undef DEBUG
+ #undef VERBOSE
+
+ #include <linux/module.h>
+@@ -23,8 +24,11 @@
+ #include <linux/ioport.h>
+ #include <linux/types.h>
+ #include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
++#include <linux/timer.h>
+ #include <linux/list.h>
+ #include <linux/interrupt.h>
+ #include <linux/proc_fs.h>
+@@ -41,9 +45,11 @@
+
+ #include <asm/byteorder.h>
+ #include <asm/io.h>
++#include <asm/irq.h>
+ #include <asm/system.h>
+ #include <asm/unaligned.h>
+ #include <asm/dma.h>
++#include <asm/cacheflush.h>
+
+ #include "fsl_usb2_udc.h"
+
+@@ -56,11 +62,11 @@
+ static const char driver_name[] = "fsl-usb2-udc";
+ static const char driver_desc[] = DRIVER_DESC;
+
+-static struct usb_dr_device *dr_regs;
+-static struct usb_sys_interface *usb_sys_regs;
++volatile static struct usb_dr_device *dr_regs;
++volatile static struct usb_sys_interface *usb_sys_regs;
+
+ /* it is initialized in probe() */
+-static struct fsl_udc *udc_controller = NULL;
++static struct fsl_udc *udc_controller;
+
+ static const struct usb_endpoint_descriptor
+ fsl_ep0_desc = {
+@@ -71,16 +77,17 @@
+ .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD,
+ };
+
++static int udc_suspend(struct fsl_udc *udc);
++static int fsl_udc_suspend(struct device *dev, pm_message_t state);
++static int fsl_udc_resume(struct device *dev);
+ static void fsl_ep_fifo_flush(struct usb_ep *_ep);
+
+-#ifdef CONFIG_PPC32
+-#define fsl_readl(addr) in_le32(addr)
+-#define fsl_writel(val32, addr) out_le32(addr, val32)
+-#else
+-#define fsl_readl(addr) readl(addr)
+-#define fsl_writel(val32, addr) writel(val32, addr)
++#ifdef CONFIG_USB_OTG
++/* Get platform resource from OTG driver */
++extern struct resource *otg_get_resources(void);
+ #endif
+
++
+ /********************************************************************
+ * Internal Used Function
+ ********************************************************************/
+@@ -174,10 +181,18 @@
+
+ static int dr_controller_setup(struct fsl_udc *udc)
+ {
+- unsigned int tmp = 0, portctrl = 0, ctrl = 0;
++ unsigned int tmp = 0, portctrl = 0;
++ unsigned int __attribute((unused)) ctrl = 0;
+ unsigned long timeout;
++ struct fsl_usb2_platform_data *pdata;
++
+ #define FSL_UDC_RESET_TIMEOUT 1000
+
++ /* before here, make sure dr_regs has been initialized */
++ if (!udc)
++ return -EINVAL;
++ pdata = udc->pdata;
++
+ /* Stop and reset the usb controller */
+ tmp = fsl_readl(&dr_regs->usbcmd);
+ tmp &= ~USB_CMD_RUN_STOP;
+@@ -191,7 +206,7 @@
+ timeout = jiffies + FSL_UDC_RESET_TIMEOUT;
+ while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) {
+ if (time_after(jiffies, timeout)) {
+- ERR("udc reset timeout!\n");
++ ERR("udc reset timeout! \n");
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+@@ -199,11 +214,16 @@
+
+ /* Set the controller as device mode */
+ tmp = fsl_readl(&dr_regs->usbmode);
++ tmp &= ~USB_MODE_CTRL_MODE_MASK; /* clear mode bits */
+ tmp |= USB_MODE_CTRL_MODE_DEVICE;
+ /* Disable Setup Lockout */
+ tmp |= USB_MODE_SETUP_LOCK_OFF;
++ if (pdata->es)
++ tmp |= USB_MODE_ES;
+ fsl_writel(tmp, &dr_regs->usbmode);
+
++ fsl_platform_set_device_mode(pdata);
++
+ /* Clear the setup status */
+ fsl_writel(0, &dr_regs->usbsts);
+
+@@ -212,7 +232,7 @@
+ fsl_writel(tmp, &dr_regs->endpointlistaddr);
+
+ VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
+- udc->ep_qh, (int)tmp,
++ (int)udc->ep_qh, (int)tmp,
+ fsl_readl(&dr_regs->endpointlistaddr));
+
+ /* Config PHY interface */
+@@ -236,20 +256,17 @@
+ }
+ fsl_writel(portctrl, &dr_regs->portsc1);
+
+- /* Config control enable i/o output, cpu endian register */
+- ctrl = __raw_readl(&usb_sys_regs->control);
+- ctrl |= USB_CTRL_IOENB;
+- __raw_writel(ctrl, &usb_sys_regs->control);
+-
+ #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+ /* Turn on cache snooping hardware, since some PowerPC platforms
+ * wholly rely on hardware to deal with cache coherent. */
+
+- /* Setup Snooping for all the 4GB space */
+- tmp = SNOOP_SIZE_2GB; /* starts from 0x0, size 2G */
+- __raw_writel(tmp, &usb_sys_regs->snoop1);
+- tmp |= 0x80000000; /* starts from 0x8000000, size 2G */
+- __raw_writel(tmp, &usb_sys_regs->snoop2);
++ if (pdata->have_sysif_regs) {
++ /* Setup Snooping for all the 4GB space */
++ tmp = SNOOP_SIZE_2GB; /* starts from 0x0, size 2G */
++ __raw_writel(tmp, &usb_sys_regs->snoop1);
++ tmp |= 0x80000000; /* starts from 0x8000000, size 2G */
++ __raw_writel(tmp, &usb_sys_regs->snoop2);
++ }
+ #endif
+
+ return 0;
+@@ -260,6 +277,8 @@
+ {
+ u32 temp;
+
++ fsl_platform_pullup_enable(udc->pdata);
++
+ /* Enable DR irq reg */
+ temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN
+ | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN
+@@ -270,11 +289,6 @@
+ /* Clear stopped bit */
+ udc->stopped = 0;
+
+- /* Set the controller as device mode */
+- temp = fsl_readl(&dr_regs->usbmode);
+- temp |= USB_MODE_CTRL_MODE_DEVICE;
+- fsl_writel(temp, &dr_regs->usbmode);
+-
+ /* Set controller to Run */
+ temp = fsl_readl(&dr_regs->usbcmd);
+ temp |= USB_CMD_RUN_STOP;
+@@ -287,6 +301,19 @@
+ {
+ unsigned int tmp;
+
++ pr_debug("%s\n", __FUNCTION__);
++
++ /* if we're in OTG mode, and the Host is currently using the port,
++ * stop now and don't rip the controller out from under the
++ * ehci driver
++ */
++ if (udc->gadget.is_otg) {
++ if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
++ pr_debug("udc: Leaving early\n");
++ return;
++ }
++ }
++
+ /* disable all INTR */
+ fsl_writel(0, &dr_regs->usbintr);
+
+@@ -296,6 +323,8 @@
+ /* disable IO output */
+ /* usb_sys_regs->control = 0; */
+
++ fsl_platform_pullup_disable(udc->pdata);
++
+ /* set controller to Stop */
+ tmp = fsl_readl(&dr_regs->usbcmd);
+ tmp &= ~USB_CMD_RUN_STOP;
+@@ -304,8 +333,7 @@
+ return;
+ }
+
+-static void dr_ep_setup(unsigned char ep_num, unsigned char dir,
+- unsigned char ep_type)
++void dr_ep_setup(unsigned char ep_num, unsigned char dir, unsigned char ep_type)
+ {
+ unsigned int tmp_epctrl = 0;
+
+@@ -404,10 +432,7 @@
+ }
+ if (zlt)
+ tmp |= EP_QUEUE_HEAD_ZLT_SEL;
+-
+- p_QH->max_pkt_length = cpu_to_le32(tmp);
+- p_QH->next_dtd_ptr = 1;
+- p_QH->size_ioc_int_sts = 0;
++ p_QH->max_pkt_length = cpu_to_hc32(tmp);
+
+ return;
+ }
+@@ -515,7 +540,7 @@
+ spin_unlock_irqrestore(&udc->lock, flags);
+ retval = 0;
+
+- VDBG("enabled %s (ep%d%s) maxpacket %d",ep->ep.name,
++ VDBG("enabled %s (ep%d%s) maxpacket %d", ep->ep.name,
+ ep->desc->bEndpointAddress & 0x0f,
+ (desc->bEndpointAddress & USB_DIR_IN)
+ ? "in" : "out", max);
+@@ -556,7 +581,7 @@
+ /* nuke all pending requests (does flush) */
+ nuke(ep, -ESHUTDOWN);
+
+- ep->desc = NULL;
++ ep->desc = 0;
+ ep->stopped = 1;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+@@ -595,7 +620,7 @@
+ }
+
+ /*-------------------------------------------------------------------------*/
+-static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
++static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
+ {
+ int i = ep_index(ep) * 2 + ep_is_in(ep);
+ u32 temp, bitmask, tmp_stat;
+@@ -614,7 +639,7 @@
+ struct fsl_req *lastreq;
+ lastreq = list_entry(ep->queue.prev, struct fsl_req, queue);
+ lastreq->tail->next_td_ptr =
+- cpu_to_le32(req->head->td_dma & DTD_ADDR_MASK);
++ cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);
+ /* Read prime bit, if 1 goto done */
+ if (fsl_readl(&dr_regs->endpointprime) & bitmask)
+ goto out;
+@@ -639,23 +664,20 @@
+
+ /* Write dQH next pointer and terminate bit to 0 */
+ temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+- dQH->next_dtd_ptr = cpu_to_le32(temp);
++ dQH->next_dtd_ptr = cpu_to_hc32(temp);
+
+ /* Clear active and halt bit */
+- temp = cpu_to_le32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
++ temp = cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
+ | EP_QUEUE_HEAD_STATUS_HALT));
+ dQH->size_ioc_int_sts &= temp;
+
+- /* Ensure that updates to the QH will occure before priming. */
+- wmb();
+-
+ /* Prime endpoint by writing 1 to ENDPTPRIME */
+ temp = ep_is_in(ep)
+ ? (1 << (ep_index(ep) + 16))
+ : (1 << (ep_index(ep)));
+ fsl_writel(temp, &dr_regs->endpointprime);
+ out:
+- return;
++ return 0;
+ }
+
+ /* Fill in the dTD structure
+@@ -680,17 +702,17 @@
+
+ dtd->td_dma = *dma;
+ /* Clear reserved field */
+- swap_temp = cpu_to_le32(dtd->size_ioc_sts);
++ swap_temp = hc32_to_cpu(dtd->size_ioc_sts);
+ swap_temp &= ~DTD_RESERVED_FIELDS;
+- dtd->size_ioc_sts = cpu_to_le32(swap_temp);
++ dtd->size_ioc_sts = cpu_to_hc32(swap_temp);
+
+ /* Init all of buffer page pointers */
+ swap_temp = (u32) (req->req.dma + req->req.actual);
+- dtd->buff_ptr0 = cpu_to_le32(swap_temp);
+- dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000);
+- dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000);
+- dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000);
+- dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000);
++ dtd->buff_ptr0 = cpu_to_hc32(swap_temp);
++ dtd->buff_ptr1 = cpu_to_hc32(swap_temp + 0x1000);
++ dtd->buff_ptr2 = cpu_to_hc32(swap_temp + 0x2000);
++ dtd->buff_ptr3 = cpu_to_hc32(swap_temp + 0x3000);
++ dtd->buff_ptr4 = cpu_to_hc32(swap_temp + 0x4000);
+
+ req->req.actual += *length;
+
+@@ -706,7 +728,7 @@
+ *is_last = 0;
+
+ if ((*is_last) == 0)
+- VDBG("multi-dtd request!");
++ VDBG("multi-dtd request!\n");
+ /* Fill in the transfer size; set active bit */
+ swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
+
+@@ -714,7 +736,7 @@
+ if (*is_last && !req->req.no_interrupt)
+ swap_temp |= DTD_IOC;
+
+- dtd->size_ioc_sts = cpu_to_le32(swap_temp);
++ dtd->size_ioc_sts = cpu_to_hc32(swap_temp);
+
+ mb();
+
+@@ -728,7 +750,7 @@
+ {
+ unsigned count;
+ int is_last;
+- int is_first =1;
++ int is_first = 1;
+ struct ep_td_struct *last_dtd = NULL, *dtd;
+ dma_addr_t dma;
+
+@@ -741,7 +763,7 @@
+ is_first = 0;
+ req->head = dtd;
+ } else {
+- last_dtd->next_td_ptr = cpu_to_le32(dma);
++ last_dtd->next_td_ptr = cpu_to_hc32(dma);
+ last_dtd->next_td_virt = dtd;
+ }
+ last_dtd = dtd;
+@@ -749,7 +771,7 @@
+ req->dtd_count++;
+ } while (!is_last);
+
+- dtd->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE);
++ dtd->next_td_ptr = cpu_to_hc32(DTD_NEXT_TERMINATE);
+
+ req->tail = dtd;
+
+@@ -769,11 +791,11 @@
+ /* catch various bogus parameters */
+ if (!_req || !req->req.complete || !req->req.buf
+ || !list_empty(&req->queue)) {
+- VDBG("%s, bad params", __func__);
++ VDBG("%s, bad params\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ if (unlikely(!_ep || !ep->desc)) {
+- VDBG("%s, bad ep", __func__);
++ VDBG("%s, bad ep\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+@@ -962,6 +984,36 @@
+ return status;
+ }
+
++static int arcotg_fifo_status(struct usb_ep *_ep)
++{
++ struct fsl_ep *ep;
++ struct fsl_udc *udc;
++ int size = 0;
++ u32 bitmask;
++ struct ep_queue_head *d_qh;
++
++ ep = container_of(_ep, struct fsl_ep, ep);
++ if (!_ep || (!ep->desc && ep_index(ep) != 0))
++ return -ENODEV;
++
++ udc = (struct fsl_udc *)ep->udc;
++
++ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
++ return -ESHUTDOWN;
++
++ d_qh = &ep->udc->ep_qh[ep_index(ep) * 2 + ep_is_in(ep)];
++
++ bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
++ (1 << (ep_index(ep)));
++
++ if (fsl_readl(&dr_regs->endptstatus) & bitmask)
++ size = (d_qh->size_ioc_int_sts & DTD_PACKET_SIZE)
++ >> DTD_LENGTH_BIT_POS;
++
++ pr_debug("%s %u\n", __FUNCTION__, size);
++ return size;
++}
++
+ static void fsl_ep_fifo_flush(struct usb_ep *_ep)
+ {
+ struct fsl_ep *ep;
+@@ -1014,6 +1066,7 @@
+ .dequeue = fsl_ep_dequeue,
+
+ .set_halt = fsl_ep_set_halt,
++ .fifo_status = arcotg_fifo_status,
+ .fifo_flush = fsl_ep_fifo_flush, /* flush fifo */
+ };
+
+@@ -1065,7 +1118,7 @@
+
+ udc = container_of(gadget, struct fsl_udc, gadget);
+ spin_lock_irqsave(&udc->lock, flags);
+- VDBG("VBUS %s", is_active ? "on" : "off");
++ VDBG("VBUS %s\n", is_active ? "on" : "off");
+ udc->vbus_active = (is_active != 0);
+ if (can_pullup(udc))
+ fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
+@@ -1142,6 +1195,7 @@
+ {
+ struct fsl_req *req = udc->status_req;
+ struct fsl_ep *ep;
++ int status = 0;
+
+ if (direction == EP_DIR_IN)
+ udc->ep0_dir = USB_DIR_IN;
+@@ -1159,21 +1213,27 @@
+ req->dtd_count = 0;
+
+ if (fsl_req_to_dtd(req) == 0)
+- fsl_queue_td(ep, req);
++ status = fsl_queue_td(ep, req);
+ else
+ return -ENOMEM;
+
++ if (status)
++ ERR("Can't queue ep0 status request \n");
+ list_add_tail(&req->queue, &ep->queue);
+
+- return 0;
++ return status;
+ }
+
+-static void udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe)
++static inline int udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe)
+ {
+ struct fsl_ep *ep = get_ep_by_pipe(udc, pipe);
+
+- if (ep->name)
+- nuke(ep, -ESHUTDOWN);
++ if (!ep->name)
++ return 0;
++
++ nuke(ep, -ESHUTDOWN);
++
++ return 0;
+ }
+
+ /*
+@@ -1197,8 +1257,10 @@
+ u16 index, u16 length)
+ {
+ u16 tmp = 0; /* Status, cpu endian */
++
+ struct fsl_req *req;
+ struct fsl_ep *ep;
++ int status = 0;
+
+ ep = &udc->eps[0];
+
+@@ -1228,6 +1290,10 @@
+ req = udc->status_req;
+ /* Fill in the reqest structure */
+ *((u16 *) req->req.buf) = cpu_to_le16(tmp);
++
++ /* flush cache for the req buffer */
++ flush_dcache_range((u32)req->req.buf, (u32)req->req.buf + 8);
++
+ req->ep = ep;
+ req->req.length = 2;
+ req->req.status = -EINPROGRESS;
+@@ -1237,10 +1303,14 @@
+
+ /* prime the data phase */
+ if ((fsl_req_to_dtd(req) == 0))
+- fsl_queue_td(ep, req);
++ status = fsl_queue_td(ep, req);
+ else /* no mem */
+ goto stall;
+
++ if (status) {
++ ERR("Can't respond to getstatus request \n");
++ goto stall;
++ }
+ list_add_tail(&req->queue, &ep->queue);
+ udc->ep0_state = DATA_STATE_XMIT;
+ return;
+@@ -1280,6 +1350,7 @@
+ /* Status phase from udc */
+ {
+ int rc = -EOPNOTSUPP;
++ u16 ptc = 0;
+
+ if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
+ == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
+@@ -1301,17 +1372,19 @@
+ | USB_TYPE_STANDARD)) {
+ /* Note: The driver has not include OTG support yet.
+ * This will be set when OTG support is added */
+- if (!gadget_is_otg(&udc->gadget))
+- break;
+- else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
+- udc->gadget.b_hnp_enable = 1;
+- else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
+- udc->gadget.a_hnp_support = 1;
+- else if (setup->bRequest ==
+- USB_DEVICE_A_ALT_HNP_SUPPORT)
+- udc->gadget.a_alt_hnp_support = 1;
+- else
+- break;
++ if (wValue == USB_DEVICE_TEST_MODE)
++ ptc = wIndex >> 8;
++ else if (gadget_is_otg(&udc->gadget)) {
++ if (setup->bRequest ==
++ USB_DEVICE_B_HNP_ENABLE)
++ udc->gadget.b_hnp_enable = 1;
++ else if (setup->bRequest ==
++ USB_DEVICE_A_HNP_SUPPORT)
++ udc->gadget.a_hnp_support = 1;
++ else if (setup->bRequest ==
++ USB_DEVICE_A_ALT_HNP_SUPPORT)
++ udc->gadget.a_alt_hnp_support = 1;
++ }
+ rc = 0;
+ } else
+ break;
+@@ -1320,6 +1393,15 @@
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ ep0stall(udc);
+ }
++ if (ptc) {
++ u32 tmp;
++
++ mdelay(10);
++ tmp = fsl_readl(&dr_regs->portsc1) | (ptc << 16);
++ fsl_writel(tmp, &dr_regs->portsc1);
++ printk(KERN_INFO "udc: switch to test mode %d.\n", ptc);
++ }
++
+ return;
+ }
+
+@@ -1380,7 +1462,7 @@
+ udc->ep0_state = WAIT_FOR_SETUP;
+ break;
+ case WAIT_FOR_SETUP:
+- ERR("Unexpect ep0 packets\n");
++ ERR("Unexpect ep0 packets \n");
+ break;
+ default:
+ ep0stall(udc);
+@@ -1394,6 +1476,7 @@
+ {
+ u32 temp;
+ struct ep_queue_head *qh;
++ struct fsl_usb2_platform_data *pdata = udc->pdata;
+
+ qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT];
+
+@@ -1408,7 +1491,16 @@
+ fsl_writel(temp | USB_CMD_SUTW, &dr_regs->usbcmd);
+
+ /* Copy the setup packet to local buffer */
+- memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
++ if (pdata->le_setup_buf) {
++ u32 *p = (u32 *)buffer_ptr;
++ u32 *s = (u32 *)qh->setup_buffer;
++
++ /* Convert little endian setup buffer to CPU endian */
++ *p++ = le32_to_cpu(*s++);
++ *p = le32_to_cpu(*s);
++ } else {
++ memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
++ }
+ } while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_SUTW));
+
+ /* Clear Setup Tripwire */
+@@ -1432,19 +1524,19 @@
+ actual = curr_req->req.length;
+
+ for (j = 0; j < curr_req->dtd_count; j++) {
+- remaining_length = (le32_to_cpu(curr_td->size_ioc_sts)
++ remaining_length = (hc32_to_cpu(curr_td->size_ioc_sts)
+ & DTD_PACKET_SIZE)
+ >> DTD_LENGTH_BIT_POS;
+ actual -= remaining_length;
+
+- if ((errors = le32_to_cpu(curr_td->size_ioc_sts) &
+- DTD_ERROR_MASK)) {
++ errors = hc32_to_cpu(curr_td->size_ioc_sts) & DTD_ERROR_MASK;
++ if (errors) {
+ if (errors & DTD_STATUS_HALTED) {
+ ERR("dTD error %08x QH=%d\n", errors, pipe);
+ /* Clear the errors and Halt condition */
+- tmp = le32_to_cpu(curr_qh->size_ioc_int_sts);
++ tmp = hc32_to_cpu(curr_qh->size_ioc_int_sts);
+ tmp &= ~errors;
+- curr_qh->size_ioc_int_sts = cpu_to_le32(tmp);
++ curr_qh->size_ioc_int_sts = cpu_to_hc32(tmp);
+ status = -EPIPE;
+ /* FIXME: continue with next queued TD? */
+
+@@ -1459,10 +1551,10 @@
+ status = -EILSEQ;
+ break;
+ } else
+- ERR("Unknown error has occured (0x%x)!\n",
++ ERR("Unknown error has occured (0x%x)!\r\n",
+ errors);
+
+- } else if (le32_to_cpu(curr_td->size_ioc_sts)
++ } else if (hc32_to_cpu(curr_td->size_ioc_sts)
+ & DTD_STATUS_ACTIVE) {
+ VDBG("Request not complete");
+ status = REQ_UNCOMPLETE;
+@@ -1478,7 +1570,7 @@
+ }
+ } else {
+ td_complete++;
+- VDBG("dTD transmitted successful");
++ VDBG("dTD transmitted successful ");
+ }
+
+ if (j != curr_req->dtd_count - 1)
+@@ -1521,7 +1613,7 @@
+
+ /* If the ep is configured */
+ if (curr_ep->name == NULL) {
+- WARNING("Invalid EP?");
++ WARN("Invalid EP?");
+ continue;
+ }
+
+@@ -1551,6 +1643,9 @@
+ {
+ u32 speed;
+
++ if (udc->bus_reset)
++ udc->bus_reset = 0;
++
+ /* Bus resetting is finished */
+ if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) {
+ /* Get the speed */
+@@ -1607,9 +1702,7 @@
+ udc_reset_ep_queue(udc, pipe);
+
+ /* report disconnect; the driver is already quiesced */
+- spin_unlock(&udc->lock);
+ udc->driver->disconnect(&udc->gadget);
+- spin_lock(&udc->lock);
+
+ return 0;
+ }
+@@ -1658,6 +1751,8 @@
+
+ if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
+ VDBG("Bus reset");
++ /* Bus is reseting */
++ udc->bus_reset = 1;
+ /* Reset all the queues, include XD, dTD, EP queue
+ * head and TR Queue */
+ reset_queues(udc);
+@@ -1735,6 +1830,7 @@
+
+ /* Reset Received */
+ if (irq_src & USB_STS_RESET) {
++ VDBG("reset int");
+ reset_irq(udc);
+ status = IRQ_HANDLED;
+ }
+@@ -1746,7 +1842,7 @@
+ }
+
+ if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) {
+- VDBG("Error IRQ %x", irq_src);
++ VDBG("Error IRQ %x ", irq_src);
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+@@ -1777,7 +1873,7 @@
+ /* lock is needed but whether should use this lock or another */
+ spin_lock_irqsave(&udc_controller->lock, flags);
+
+- driver->driver.bus = NULL;
++ driver->driver.bus = 0;
+ /* hook up the driver */
+ udc_controller->driver = driver;
+ udc_controller->gadget.dev.driver = &driver->driver;
+@@ -1787,22 +1883,45 @@
+ retval = driver->bind(&udc_controller->gadget);
+ if (retval) {
+ VDBG("bind to %s --> %d", driver->driver.name, retval);
+- udc_controller->gadget.dev.driver = NULL;
+- udc_controller->driver = NULL;
++ udc_controller->gadget.dev.driver = 0;
++ udc_controller->driver = 0;
+ goto out;
+ }
+
+- /* Enable DR IRQ reg and Set usbcmd reg Run bit */
+- dr_controller_run(udc_controller);
+- udc_controller->usb_state = USB_STATE_ATTACHED;
+- udc_controller->ep0_state = WAIT_FOR_SETUP;
+- udc_controller->ep0_dir = 0;
+- printk(KERN_INFO "%s: bind to driver %s\n",
++ if (udc_controller->transceiver) {
++ /* Suspend the controller until OTG enable it */
++ udc_controller->stopped = 1;
++ printk(KERN_INFO "Suspend udc for OTG auto detect\n");
++
++ /* export udc suspend/resume call to OTG */
++ udc_controller->gadget.dev.driver->suspend = fsl_udc_suspend;
++ udc_controller->gadget.dev.driver->resume = fsl_udc_resume;
++
++ /* connect to bus through transceiver */
++ if (udc_controller->transceiver) {
++ retval = otg_set_peripheral(udc_controller->transceiver,
++ &udc_controller->gadget);
++ if (retval < 0) {
++ ERR("can't bind to transceiver\n");
++ driver->unbind(&udc_controller->gadget);
++ udc_controller->gadget.dev.driver = 0;
++ udc_controller->driver = 0;
++ return retval;
++ }
++ }
++ } else {
++ /* Enable DR IRQ reg and Set usbcmd reg Run bit */
++ dr_controller_run(udc_controller);
++ udc_controller->usb_state = USB_STATE_ATTACHED;
++ udc_controller->ep0_state = WAIT_FOR_SETUP;
++ udc_controller->ep0_dir = 0;
++ }
++ printk(KERN_INFO "%s: bind to driver %s \n",
+ udc_controller->gadget.name, driver->driver.name);
+
+ out:
+ if (retval)
+- printk("gadget driver register failed %d\n", retval);
++ printk(KERN_DEBUG "retval %d \n", retval);
+ return retval;
+ }
+ EXPORT_SYMBOL(usb_gadget_register_driver);
+@@ -1820,7 +1939,7 @@
+ return -EINVAL;
+
+ if (udc_controller->transceiver)
+- otg_set_peripheral(udc_controller->transceiver, NULL);
++ (void)otg_set_peripheral(udc_controller->transceiver, 0);
+
+ /* stop DR, disable intr */
+ dr_controller_stop(udc_controller);
+@@ -1839,15 +1958,13 @@
+ nuke(loop_ep, -ESHUTDOWN);
+ spin_unlock_irqrestore(&udc_controller->lock, flags);
+
+- /* report disconnect; the controller is already quiesced */
+- driver->disconnect(&udc_controller->gadget);
+-
+ /* unbind gadget and unhook driver. */
+ driver->unbind(&udc_controller->gadget);
+- udc_controller->gadget.dev.driver = NULL;
+- udc_controller->driver = NULL;
++ udc_controller->gadget.dev.driver = 0;
++ udc_controller->driver = 0;
+
+- printk("unregistered gadget driver '%s'\n", driver->driver.name);
++ printk(KERN_INFO "unregistered gadget driver '%s'\r\n",
++ driver->driver.name);
+ return 0;
+ }
+ EXPORT_SYMBOL(usb_gadget_unregister_driver);
+@@ -1872,14 +1989,16 @@
+ u32 tmp_reg;
+ struct fsl_ep *ep = NULL;
+ struct fsl_req *req;
++ struct fsl_usb2_platform_data *pdata;
+
+ struct fsl_udc *udc = udc_controller;
++ pdata = udc->pdata;
+ if (off != 0)
+ return 0;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+- /* ------basic driver information ---- */
++ /* ------basic driver infomation ---- */
+ t = scnprintf(next, size,
+ DRIVER_DESC "\n"
+ "%s version: %s\n"
+@@ -1903,7 +2022,7 @@
+ tmp_reg = fsl_readl(&dr_regs->usbsts);
+ t = scnprintf(next, size,
+ "USB Status Reg:\n"
+- "Dr Suspend: %d Reset Received: %d System Error: %s "
++ "Dr Suspend: %d" "Reset Received: %d" "System Error: %s"
+ "USB Error Interrupt: %s\n\n",
+ (tmp_reg & USB_STS_SUSPEND) ? 1 : 0,
+ (tmp_reg & USB_STS_RESET) ? 1 : 0,
+@@ -1915,11 +2034,11 @@
+ tmp_reg = fsl_readl(&dr_regs->usbintr);
+ t = scnprintf(next, size,
+ "USB Intrrupt Enable Reg:\n"
+- "Sleep Enable: %d SOF Received Enable: %d "
++ "Sleep Enable: %d" "SOF Received Enable: %d"
+ "Reset Enable: %d\n"
+- "System Error Enable: %d "
++ "System Error Enable: %d"
+ "Port Change Dectected Enable: %d\n"
+- "USB Error Intr Enable: %d USB Intr Enable: %d\n\n",
++ "USB Error Intr Enable: %d" "USB Intr Enable: %d\n\n",
+ (tmp_reg & USB_INTR_DEVICE_SUSPEND) ? 1 : 0,
+ (tmp_reg & USB_INTR_SOF_EN) ? 1 : 0,
+ (tmp_reg & USB_INTR_RESET_EN) ? 1 : 0,
+@@ -1932,21 +2051,21 @@
+
+ tmp_reg = fsl_readl(&dr_regs->frindex);
+ t = scnprintf(next, size,
+- "USB Frame Index Reg: Frame Number is 0x%x\n\n",
++ "USB Frame Index Reg:" "Frame Number is 0x%x\n\n",
+ (tmp_reg & USB_FRINDEX_MASKS));
+ size -= t;
+ next += t;
+
+ tmp_reg = fsl_readl(&dr_regs->deviceaddr);
+ t = scnprintf(next, size,
+- "USB Device Address Reg: Device Addr is 0x%x\n\n",
++ "USB Device Address Reg:" "Device Addr is 0x%x\n\n",
+ (tmp_reg & USB_DEVICE_ADDRESS_MASK));
+ size -= t;
+ next += t;
+
+ tmp_reg = fsl_readl(&dr_regs->endpointlistaddr);
+ t = scnprintf(next, size,
+- "USB Endpoint List Address Reg: "
++ "USB Endpoint List Address Reg:"
+ "Device Addr is 0x%x\n\n",
+ (tmp_reg & USB_EP_LIST_ADDRESS_MASK));
+ size -= t;
+@@ -1955,12 +2074,11 @@
+ tmp_reg = fsl_readl(&dr_regs->portsc1);
+ t = scnprintf(next, size,
+ "USB Port Status&Control Reg:\n"
+- "Port Transceiver Type : %s Port Speed: %s\n"
+- "PHY Low Power Suspend: %s Port Reset: %s "
+- "Port Suspend Mode: %s\n"
+- "Over-current Change: %s "
++ "Port Transceiver Type : %s" "Port Speed: %s \n"
++ "PHY Low Power Suspend: %s" "Port Reset: %s"
++ "Port Suspend Mode: %s \n" "Over-current Change: %s"
+ "Port Enable/Disable Change: %s\n"
+- "Port Enabled/Disabled: %s "
++ "Port Enabled/Disabled: %s"
+ "Current Connect Status: %s\n\n", ( {
+ char *s;
+ switch (tmp_reg & PORTSCX_PTS_FSLS) {
+@@ -2005,7 +2123,7 @@
+
+ tmp_reg = fsl_readl(&dr_regs->usbmode);
+ t = scnprintf(next, size,
+- "USB Mode Reg: Controller Mode is: %s\n\n", ( {
++ "USB Mode Reg:" "Controller Mode is : %s\n\n", ( {
+ char *s;
+ switch (tmp_reg & USB_MODE_CTRL_MODE_HOST) {
+ case USB_MODE_CTRL_MODE_IDLE:
+@@ -2024,7 +2142,7 @@
+
+ tmp_reg = fsl_readl(&dr_regs->endptsetupstat);
+ t = scnprintf(next, size,
+- "Endpoint Setup Status Reg: SETUP on ep 0x%x\n\n",
++ "Endpoint Setup Status Reg:" "SETUP on ep 0x%x\n\n",
+ (tmp_reg & EP_SETUP_STATUS_MASK));
+ size -= t;
+ next += t;
+@@ -2037,20 +2155,22 @@
+ next += t;
+ }
+ tmp_reg = fsl_readl(&dr_regs->endpointprime);
+- t = scnprintf(next, size, "EP Prime Reg = [0x%x]\n\n", tmp_reg);
++ t = scnprintf(next, size, "EP Prime Reg = [0x%x]\n", tmp_reg);
+ size -= t;
+ next += t;
+
+- tmp_reg = usb_sys_regs->snoop1;
+- t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg);
+- size -= t;
+- next += t;
++ if (pdata->have_sysif_regs) {
++ tmp_reg = usb_sys_regs->snoop1;
++ t = scnprintf(next, size, "\nSnoop1 Reg = [0x%x]\n\n", tmp_reg);
++ size -= t;
++ next += t;
+
+- tmp_reg = usb_sys_regs->control;
+- t = scnprintf(next, size, "General Control Reg : = [0x%x]\n\n",
+- tmp_reg);
+- size -= t;
+- next += t;
++ tmp_reg = usb_sys_regs->control;
++ t = scnprintf(next, size, "General Control Reg = [0x%x]\n\n",
++ tmp_reg);
++ size -= t;
++ next += t;
++ }
+
+ /* ------fsl_udc, fsl_ep, fsl_request structure information ----- */
+ ep = &udc->eps[0];
+@@ -2066,7 +2186,7 @@
+ } else {
+ list_for_each_entry(req, &ep->queue, queue) {
+ t = scnprintf(next, size,
+- "req %p actual 0x%x length 0x%x buf %p\n",
++ "req %p actual 0x%x length 0x%x buf %p\n",
+ &req->req, req->req.actual,
+ req->req.length, req->req.buf);
+ size -= t;
+@@ -2092,13 +2212,13 @@
+ } else {
+ list_for_each_entry(req, &ep->queue, queue) {
+ t = scnprintf(next, size,
+- "req %p actual 0x%x length "
++ "req %p actual 0x%x length"
+ "0x%x buf %p\n",
+ &req->req, req->req.actual,
+ req->req.length, req->req.buf);
+ size -= t;
+ next += t;
+- } /* end for each_entry of ep req */
++ } /* end for each_entry of ep req */
+ } /* end for else */
+ } /* end for if(ep->queue) */
+ } /* end (ep->desc) */
+@@ -2184,6 +2304,7 @@
+ udc->usb_state = USB_STATE_POWERED;
+ udc->ep0_dir = 0;
+ udc->remote_wakeup = 0; /* default to 0 on reset */
++ spin_lock_init(&udc->lock);
+
+ return 0;
+ }
+@@ -2230,12 +2351,13 @@
+ static int __init fsl_udc_probe(struct platform_device *pdev)
+ {
+ struct resource *res;
++ struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+ int ret = -ENODEV;
+ unsigned int i;
+ u32 dccparams;
+
+ if (strcmp(pdev->name, driver_name)) {
+- VDBG("Wrong device");
++ VDBG("Wrong device\n");
+ return -ENODEV;
+ }
+
+@@ -2244,67 +2366,100 @@
+ ERR("malloc udc failed\n");
+ return -ENOMEM;
+ }
++ udc_controller->pdata = pdata;
+
+- spin_lock_init(&udc_controller->lock);
+- udc_controller->stopped = 1;
++#ifdef CONFIG_USB_OTG
++ /* Memory and interrupt resources will be passed from OTG */
++ udc_controller->transceiver = otg_get_transceiver();
++ if (!udc_controller->transceiver) {
++ printk(KERN_ERR "Can't find OTG driver!\n");
++ ret = -ENODEV;
++ goto err1a;
++ }
+
++ res = otg_get_resources();
++ if (!res) {
++ DBG("resource not registered!\n");
++ return -ENODEV;
++ }
++#else
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENXIO;
+- goto err_kfree;
++ goto err1a;
+ }
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ driver_name)) {
+- ERR("request mem region for %s failed\n", pdev->name);
++ ERR("request mem region for %s failed \n", pdev->name);
+ ret = -EBUSY;
+- goto err_kfree;
++ goto err1a;
+ }
+-
++#endif
+ dr_regs = ioremap(res->start, res->end - res->start + 1);
+ if (!dr_regs) {
+ ret = -ENOMEM;
+- goto err_release_mem_region;
++ goto err1;
++ }
++ pdata->regs = (void *)dr_regs;
++
++ fsl_set_usb_accessors(pdata);
++
++ /*
++ * do platform specific init: check the clock, grab/config pins, etc.
++ */
++ if (pdata->platform_init && pdata->platform_init(pdev)) {
++ ret = -ENODEV;
++ goto err2a;
+ }
+
+- usb_sys_regs = (struct usb_sys_interface *)
+- ((u32)dr_regs + USB_DR_SYS_OFFSET);
++ if (pdata->have_sysif_regs)
++ usb_sys_regs = (struct usb_sys_interface *)
++ ((u32)dr_regs + USB_DR_SYS_OFFSET);
+
+ /* Read Device Controller Capability Parameters register */
+ dccparams = fsl_readl(&dr_regs->dccparams);
+ if (!(dccparams & DCCPARAMS_DC)) {
+ ERR("This SOC doesn't support device role\n");
+ ret = -ENODEV;
+- goto err_iounmap;
++ goto err2;
+ }
++ fsl_writel(0x2, pdata->regs+0x90);
+ /* Get max device endpoints */
+ /* DEN is bidirectional ep number, max_ep doubles the number */
+ udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2;
+
++#ifdef CONFIG_USB_OTG
++ res++;
++ udc_controller->irq = res->start;
++#else
+ udc_controller->irq = platform_get_irq(pdev, 0);
++#endif
+ if (!udc_controller->irq) {
+ ret = -ENODEV;
+- goto err_iounmap;
++ goto err2;
+ }
+
+ ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED,
+ driver_name, udc_controller);
+ if (ret != 0) {
+- ERR("cannot request irq %d err %d\n",
++ ERR("cannot request irq %d err %d \n",
+ udc_controller->irq, ret);
+- goto err_iounmap;
++ goto err2;
+ }
+
+ /* Initialize the udc structure including QH member and other member */
+ if (struct_udc_setup(udc_controller, pdev)) {
+ ERR("Can't initialize udc data structure\n");
+ ret = -ENOMEM;
+- goto err_free_irq;
++ goto err3;
+ }
+
+- /* initialize usb hw reg except for regs for EP,
+- * leave usbintr reg untouched */
+- dr_controller_setup(udc_controller);
++ if (!udc_controller->transceiver) {
++ /* initialize usb hw reg except for regs for EP,
++ * leave usbintr reg untouched */
++ dr_controller_setup(udc_controller);
++ }
+
+ /* Setup gadget structure */
+ udc_controller->gadget.ops = &fsl_gadget_ops;
+@@ -2315,12 +2470,15 @@
+ udc_controller->gadget.name = driver_name;
+
+ /* Setup gadget.dev and register with kernel */
+- dev_set_name(&udc_controller->gadget.dev, "gadget");
++ strcpy(udc_controller->gadget.dev.bus_id, "gadget");
+ udc_controller->gadget.dev.release = fsl_udc_release;
+ udc_controller->gadget.dev.parent = &pdev->dev;
+ ret = device_register(&udc_controller->gadget.dev);
+ if (ret < 0)
+- goto err_free_irq;
++ goto err3;
++
++ if (udc_controller->transceiver)
++ udc_controller->gadget.is_otg = 1;
+
+ /* setup QH and epctrl for ep0 */
+ ep0_setup(udc_controller);
+@@ -2350,20 +2508,24 @@
+ DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
+ if (udc_controller->td_pool == NULL) {
+ ret = -ENOMEM;
+- goto err_unregister;
++ goto err4;
+ }
+ create_proc_file();
+ return 0;
+
+-err_unregister:
++err4:
+ device_unregister(&udc_controller->gadget.dev);
+-err_free_irq:
++err3:
+ free_irq(udc_controller->irq, udc_controller);
+-err_iounmap:
++err2:
++ if (pdata->platform_uninit)
++ pdata->platform_uninit(pdata);
++err2a:
+ iounmap(dr_regs);
+-err_release_mem_region:
+- release_mem_region(res->start, res->end - res->start + 1);
+-err_kfree:
++err1:
++ if (!udc_controller->transceiver)
++ release_mem_region(res->start, res->end - res->start + 1);
++err1a:
+ kfree(udc_controller);
+ udc_controller = NULL;
+ return ret;
+@@ -2374,7 +2536,8 @@
+ */
+ static int __exit fsl_udc_remove(struct platform_device *pdev)
+ {
+- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ struct resource __attribute((unused)) *res;
++ struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+
+ DECLARE_COMPLETION(done);
+
+@@ -2393,12 +2556,58 @@
+ dma_pool_destroy(udc_controller->td_pool);
+ free_irq(udc_controller->irq, udc_controller);
+ iounmap(dr_regs);
++
++#ifndef CONFIG_USB_OTG
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
++#endif
+
+ device_unregister(&udc_controller->gadget.dev);
+ /* free udc --wait for the release() finished */
+ wait_for_completion(&done);
+
++ /*
++ * do platform specific un-initialization:
++ * release iomux pins, etc.
++ */
++ if (pdata->platform_uninit)
++ pdata->platform_uninit(pdata);
++
++ return 0;
++}
++
++static int udc_suspend(struct fsl_udc *udc)
++{
++ u32 mode, usbcmd;
++
++ mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK;
++ usbcmd = fsl_readl(&dr_regs->usbcmd);
++
++ pr_debug("%s(): mode 0x%x stopped %d\n", __func__, mode, udc->stopped);
++
++ /*
++ * If the controller is already stopped, then this must be a
++ * PM suspend. Remember this fact, so that we will leave the
++ * controller stopped at PM resume time.
++ */
++ if (udc->stopped) {
++ pr_debug("gadget already stopped, leaving early\n");
++ udc->already_stopped = 1;
++ return 0;
++ }
++
++ if (mode != USB_MODE_CTRL_MODE_DEVICE) {
++ pr_debug("gadget not in device mode, leaving early\n");
++ return 0;
++ }
++
++ printk(KERN_INFO "USB Gadget suspended\n");
++
++ /* stop the controller */
++ usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP;
++ fsl_writel(usbcmd, &dr_regs->usbcmd);
++
++ udc->stopped = 1;
+ return 0;
+ }
+
+@@ -2406,18 +2615,30 @@
+ * Modify Power management attributes
+ * Used by OTG statemachine to disable gadget temporarily
+ -----------------------------------------------------------------*/
+-static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state)
++static int fsl_udc_suspend(struct device *dev, pm_message_t state)
+ {
+- dr_controller_stop(udc_controller);
+- return 0;
++ return udc_suspend(udc_controller);
+ }
+
+ /*-----------------------------------------------------------------
+ * Invoked on USB resume. May be called in_interrupt.
+ * Here we start the DR controller and enable the irq
+ *-----------------------------------------------------------------*/
+-static int fsl_udc_resume(struct platform_device *pdev)
++static int fsl_udc_resume(struct device *dev)
+ {
++ pr_debug("%s(): stopped %d already_stopped %d\n", __func__,
++ udc_controller->stopped, udc_controller->already_stopped);
++
++ /*
++ * If the controller was stopped at suspend time, then
++ * don't resume it now.
++ */
++ if (udc_controller->already_stopped) {
++ udc_controller->already_stopped = 0;
++ pr_debug("gadget was already stopped, leaving early\n");
++ return 0;
++ }
++
+ /* Enable DR irq reg and set controller Run */
+ if (udc_controller->stopped) {
+ dr_controller_setup(udc_controller);
+@@ -2426,6 +2647,8 @@
+ udc_controller->usb_state = USB_STATE_ATTACHED;
+ udc_controller->ep0_state = WAIT_FOR_SETUP;
+ udc_controller->ep0_dir = 0;
++
++ printk(KERN_INFO "USB Gadget resumed\n");
+ return 0;
+ }
+
+@@ -2438,8 +2661,9 @@
+ /* these suspend and resume are not usb suspend and resume */
+ .suspend = fsl_udc_suspend,
+ .resume = fsl_udc_resume,
++ .probe = fsl_udc_probe,
+ .driver = {
+- .name = (char *)driver_name,
++ .name = driver_name,
+ .owner = THIS_MODULE,
+ },
+ };
+@@ -2447,7 +2671,7 @@
+ static int __init udc_init(void)
+ {
+ printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION);
+- return platform_driver_probe(&udc_driver, fsl_udc_probe);
++ return platform_driver_register(&udc_driver);
+ }
+
+ module_init(udc_init);
+@@ -2455,7 +2679,7 @@
+ static void __exit udc_exit(void)
+ {
+ platform_driver_unregister(&udc_driver);
+- printk("%s unregistered\n", driver_desc);
++ printk(KERN_INFO "%s unregistered \n", driver_desc);
+ }
+
+ module_exit(udc_exit);
+@@ -2463,4 +2687,3 @@
+ MODULE_DESCRIPTION(DRIVER_DESC);
+ MODULE_AUTHOR(DRIVER_AUTHOR);
+ MODULE_LICENSE("GPL");
+-MODULE_ALIAS("platform:fsl-usb2-udc");
+diff -Naur linux-2.6.29/drivers/usb/gadget/fsl_usb2_udc.h linux-2.6.29-v2010041601/drivers/usb/gadget/fsl_usb2_udc.h
+--- linux-2.6.29/drivers/usb/gadget/fsl_usb2_udc.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/usb/gadget/fsl_usb2_udc.h 2010-04-13 20:23:26.000000000 +0200
+@@ -1,4 +1,15 @@
+ /*
++ * Copyright (C) 2004-2008 Freescale Semicondutor, Inc. All rights reserved.
++ *
++ * Author: Li Yang <leoli@freescale.com>
++ * Jiang Bo <tanya.jiang@freescale.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++/*
+ * Freescale USB device/endpoint management registers
+ */
+ #ifndef __FSL_USB2_UDC_H
+@@ -8,6 +19,8 @@
+ */
+ #define USB_MAX_CTRL_PAYLOAD 64
+ #define USB_DR_SYS_OFFSET 0x400
++#define USBGENCTRL_OFFSET 0x200
++#define ISIPHYCTRL_OFFSET 0x204
+
+ /* USB DR device mode registers (Little Endian) */
+ struct usb_dr_device {
+@@ -275,7 +288,9 @@
+ #define USB_MODE_CTRL_MODE_IDLE 0x00000000
+ #define USB_MODE_CTRL_MODE_DEVICE 0x00000002
+ #define USB_MODE_CTRL_MODE_HOST 0x00000003
++#define USB_MODE_CTRL_MODE_MASK 0x00000003
+ #define USB_MODE_CTRL_MODE_RSV 0x00000001
++#define USB_MODE_ES 0x00000004 /* (big) Endian Select */
+ #define USB_MODE_SETUP_LOCK_OFF 0x00000008
+ #define USB_MODE_STREAM_DISABLE 0x00000010
+ /* Endpoint Flush Register */
+@@ -424,6 +439,16 @@
+ /* Controller dma boundary */
+ #define UDC_DMA_BOUNDARY 0x1000
+
++/* -----------------------------------------------------------------------*/
++/* ##### enum data
++*/
++typedef enum {
++ e_ULPI,
++ e_UTMI_8BIT,
++ e_UTMI_16BIT,
++ e_SERIAL
++} e_PhyInterface;
++
+ /*-------------------------------------------------------------------------*/
+
+ /* ### driver private data
+@@ -461,7 +486,7 @@
+ struct fsl_udc {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+- struct completion *done; /* to make sure release() is done */
++ struct fsl_usb2_platform_data *pdata;
+ struct fsl_ep *eps;
+ unsigned int max_ep;
+ unsigned int irq;
+@@ -473,6 +498,7 @@
+ unsigned vbus_active:1;
+ unsigned stopped:1;
+ unsigned remote_wakeup:1;
++ unsigned already_stopped:1;
+
+ struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */
+ struct fsl_req *status_req; /* ep0 status request */
+@@ -482,22 +508,29 @@
+ size_t ep_qh_size; /* size after alignment adjustment*/
+ dma_addr_t ep_qh_dma; /* dma address of QH */
+
+- u32 max_pipes; /* Device max pipes */
++ u32 max_pipes; /* Device max pipes */
++ u32 max_use_endpts; /* Max endpointes to be used */
++ u32 bus_reset; /* Device is bus reseting */
+ u32 resume_state; /* USB state to resume */
+ u32 usb_state; /* USB current state */
++ u32 usb_next_state; /* USB next state */
+ u32 ep0_state; /* Endpoint zero state */
+ u32 ep0_dir; /* Endpoint zero direction: can be
+ USB_DIR_IN or USB_DIR_OUT */
++ u32 usb_sof_count; /* SOF count */
++ u32 errors; /* USB ERRORs count */
+ u8 device_address; /* Device USB address */
++
++ struct completion *done; /* to make sure release() is done */
+ };
+
+ /*-------------------------------------------------------------------------*/
+
+ #ifdef DEBUG
+ #define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt "\n", \
+- __func__, ## args)
++ __FUNCTION__, ## args)
+ #else
+-#define DBG(fmt, args...) do{}while(0)
++#define DBG(fmt, args...) do {} while (0)
+ #endif
+
+ #if 0
+@@ -531,12 +564,12 @@
+ #ifdef VERBOSE
+ #define VDBG DBG
+ #else
+-#define VDBG(stuff...) do{}while(0)
++#define VDBG(stuff...) do {} while (0)
+ #endif
+
+-#define ERR(stuff...) pr_err("udc: " stuff)
+-#define WARNING(stuff...) pr_warning("udc: " stuff)
+-#define INFO(stuff...) pr_info("udc: " stuff)
++#define ERR(stuff...) printk(KERN_ERR "udc: " stuff)
++#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
++#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
+
+ /*-------------------------------------------------------------------------*/
+
+@@ -546,8 +579,8 @@
+ /*
+ * ### pipe direction macro from device view
+ */
+-#define USB_RECV 0 /* OUT EP */
+-#define USB_SEND 1 /* IN EP */
++#define USB_RECV (0) /* OUT EP */
++#define USB_SEND (1) /* IN EP */
+
+ /*
+ * ### internal used help routines.
+@@ -563,4 +596,14 @@
+ * 2 + ((windex & USB_DIR_IN) ? 1 : 0))
+ #define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP))
+
++#ifdef CONFIG_ARCH_MXC
++#include <asm/arch/fsl_usb_gadget.h>
++#elif CONFIG_PPC32
++#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
++#define CONFIG_USB_FSL_BIG_ENDIAN_DESC 1
++#endif
++#include <asm/fsl_usb_io.h>
++#include <asm/fsl_usb_gadget.h>
++#endif
++
+ #endif
+diff -Naur linux-2.6.29/drivers/usb/host/ehci-fsl.c linux-2.6.29-v2010041601/drivers/usb/host/ehci-fsl.c
+--- linux-2.6.29/drivers/usb/host/ehci-fsl.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/usb/host/ehci-fsl.c 2010-04-13 20:23:26.000000000 +0200
+@@ -25,8 +25,97 @@
+ #include "ehci-fsl.h"
+
+ /* FIXME: Power Management is un-ported so temporarily disable it */
+-#undef CONFIG_PM
++#define EHCI_PROC_PTC
+
++#ifdef EHCI_PROC_PTC /* /proc PORTSC:PTC support */
++#include <asm/uaccess.h>
++#define EFPSL 3 /* ehci fsl proc string length */
++
++#if 0
++#define DBGMsg(x...) printk(x)
++#define DBG() printk("---%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__)
++#else
++#define DBGMsg(x...)
++#define DBG()
++#endif
++
++static int ehci_fsl_proc_read(char *page, char **start, off_t off, int count,
++ int *eof, void *data)
++{
++ return 0;
++}
++
++static int ehci_fsl_proc_write(struct file *file, const char __user *buffer,
++ unsigned long count, void *data)
++{
++ int ptc;
++ u32 portsc;
++ struct ehci_hcd *ehci = (struct ehci_hcd *) data;
++ char str[EFPSL] = {0};
++
++ if (count > EFPSL-1)
++ return -EINVAL;
++
++ if (copy_from_user(str, buffer, count))
++ return -EFAULT;
++
++ str[count] = '\0';
++
++ ptc = simple_strtoul(str, NULL, 0);
++
++ portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
++ portsc &= ~(0xf << 16);
++ portsc |= (ptc << 16);
++ printk(KERN_INFO "PTC %x portsc %08x\n", ptc, portsc);
++
++ ehci_writel(ehci, portsc, &ehci->regs->port_status[0]);
++
++ return count;
++}
++
++static int ehci_testmode_init(struct ehci_hcd *ehci)
++{
++ struct proc_dir_entry *entry;
++
++ entry = create_proc_read_entry("driver/ehci-ptc", 0644, NULL,
++ ehci_fsl_proc_read, ehci);
++ if (!entry)
++ return -ENODEV;
++
++ entry->write_proc = ehci_fsl_proc_write;
++ return 0;
++}
++#else
++static int ehci_testmode_init(struct ehci_hcd *ehci)
++{
++ return 0;
++}
++#endif /* /proc PORTSC:PTC support */
++#ifdef CONFIG_MPC5125_TWR
++/*added by Cloudy Chen <chen_yunsong@mtcera.com*/
++struct usb3320_register_data{
++unsigned char addr;
++unsigned char value;
++};
++static struct usb3320_register_data usb3320_init[]=
++{
++{0x07,0x08},
++{0x0a,0x06}
++};
++static void usb3320_reset(struct usb_hcd *hcd)
++{
++
++ unsigned int cmd,i;
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ /*read ulpi face*/
++ for(i=0;i<sizeof(usb3320_init)/sizeof(usb3320_init[0]);i++)
++ {
++ cmd=0x60000000|(usb3320_init[i].addr<<16)|(usb3320_init[i].value);
++ ehci_writel(ehci, cmd,(hcd->regs+0x170));
++ udelay(100);
++ }
++}
++#endif
+
+ /* configure so an HC device and id are always provided */
+ /* always called with process context; sleeping is OK */
+@@ -51,7 +140,7 @@
+ unsigned int temp;
+
+ pr_debug("initializing FSL-SOC USB Controller\n");
+-
++
+ /* Need platform data for setup */
+ pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data;
+ if (!pdata) {
+@@ -73,56 +162,72 @@
+ return -ENODEV;
+ }
+
+- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+- if (!res) {
+- dev_err(&pdev->dev,
+- "Found HC with no IRQ. Check %s setup!\n",
+- dev_name(&pdev->dev));
+- return -ENODEV;
+- }
+- irq = res->start;
+-
+ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto err1;
+ }
+
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- if (!res) {
+- dev_err(&pdev->dev,
+- "Found HC with no register addr. Check %s setup!\n",
+- dev_name(&pdev->dev));
+- retval = -ENODEV;
+- goto err2;
+- }
+- hcd->rsrc_start = res->start;
+- hcd->rsrc_len = res->end - res->start + 1;
+- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+- driver->description)) {
+- dev_dbg(&pdev->dev, "controller already in use\n");
+- retval = -EBUSY;
+- goto err2;
++ {
++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (!res) {
++ dev_err(&pdev->dev,
++ "Found HC with no IRQ. Check %s setup!\n",
++ dev_name(&pdev->dev));
++ retval = -ENODEV;
++ goto err2;
++ }
++ irq = res->start;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ hcd->rsrc_start = res->start;
++ hcd->rsrc_len = res->end - res->start + 1;
++
++ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
++ driver->description)) {
++ dev_err(&pdev->dev, "controller already in use\n");
++ retval = -EBUSY;
++ goto err2;
++ }
+ }
++
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+
+ if (hcd->regs == NULL) {
+- dev_dbg(&pdev->dev, "error mapping memory\n");
++ dev_err(&pdev->dev, "error mapping memory\n");
+ retval = -EFAULT;
+ goto err3;
+ }
++ pdata->regs = hcd->regs;
+
+- /* Enable USB controller */
+- temp = in_be32(hcd->regs + 0x500);
+- out_be32(hcd->regs + 0x500, temp | 0x4);
+-
++ /*
++ * do platform specific init: check the clock, grab/config pins, etc.
++ */
++ if (pdata->platform_init && pdata->platform_init(pdev)) {
++ retval = -ENODEV;
++ goto err3;
++ }
++#if 0
++ if (pdata->have_sysif_regs) {
++ /* Enable USB controller */
++ temp = in_be32(hcd->regs + FSL_SOC_USB_CTRL);
++ out_be32(hcd->regs + FSL_SOC_USB_CTRL, temp | 0x4);
++ }
++#endif
+ /* Set to Host mode */
+- temp = in_le32(hcd->regs + 0x1a8);
+- out_le32(hcd->regs + 0x1a8, temp | 0x3);
++ temp = in_le32(hcd->regs + FSL_SOC_USB_USBMODE);
++ temp |= USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
++ out_le32(hcd->regs + FSL_SOC_USB_USBMODE, temp);
+
++ /*out_le32(hcd->regs + FSL_SOC_USB_BURSTSIZE, 0x1010);*/
+ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ if (retval != 0)
+ goto err4;
++
++ ehci_testmode_init(hcd_to_ehci(hcd));
++#ifdef CONFIG_MPC5125_TWR
++ usb3320_reset(hcd);
++#endif
+ return retval;
+
+ err4:
+@@ -133,6 +238,8 @@
+ usb_put_hcd(hcd);
+ err1:
+ dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
++ if (pdata->platform_uninit)
++ pdata->platform_uninit(pdata);
+ return retval;
+ }
+
+@@ -178,21 +285,24 @@
+ }
+ ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
+ }
+-
++static void fsl_setup_phy(struct ehci_hcd *ehci, enum fsl_usb2_phy_modes phy_mode, int port_offset)
++{
++ mpc83xx_setup_phy(ehci,phy_mode,port_offset);
++}
+ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
+ {
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct fsl_usb2_platform_data *pdata;
+ void __iomem *non_ehci = hcd->regs;
+- u32 temp;
++ u32 tmp;
++
++ pdata = hcd->self.controller->platform_data;
+
+- pdata =
+- (struct fsl_usb2_platform_data *)hcd->self.controller->
+- platform_data;
+ /* Enable PHY interface in the control reg. */
+- temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+- out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
+- out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
++ if (pdata->have_sysif_regs) {
++ out_be32(non_ehci + FSL_SOC_USB_CTRL, 0x00000004);
++ out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
++ }
+
+ #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+ /*
+@@ -229,34 +339,57 @@
+ }
+
+ /* put controller in host mode. */
+- ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+-#ifdef CONFIG_PPC_85xx
+- out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
+- out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
+-#else
+- out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
+- out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
+-#endif
+- out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
++ tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
++ ehci_writel(ehci, tmp, non_ehci + FSL_SOC_USB_USBMODE);
++
++ if (pdata->have_sysif_regs) {
++ out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
++ out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
++ out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
++ }
+ }
+
+ /* called after powerup, by probe or system-pm "wakeup" */
+ static int ehci_fsl_reinit(struct ehci_hcd *ehci)
+ {
+- mpc83xx_usb_setup(ehci_to_hcd(ehci));
++ /*mpc83xx_usb_setup(ehci_to_hcd(ehci));*/
++ fsl_platform_usb_setup(ehci);
++ /*printk("%s() line:%d\n",__func__,__LINE__);*/
+ ehci_port_power(ehci, 0);
+-
+ return 0;
+ }
+-
++static void ehci_fsl_sbusconfig(struct ehci_hcd *ehci)
++{
++ struct usb_hcd *hcd;
++ hcd=ehci_to_hcd(ehci);
++ if(ehci->big_endian_mmio)
++ {
++ ehci_writel(ehci, SBUSCFG_INCR8, hcd->regs + FSL_SOC_USB_SBUSCFG);
++ if(ehci_readl(ehci, hcd->regs + FSL_SOC_USB_SBUSCFG)!=SBUSCFG_INCR8)
++ {
++ ehci_writel(ehci, SBUSCFG_INCR8, hcd->regs + FSL_SOC_USB_SBUSCFG);
++ printk(KERN_ERR"USB_SBUSCFG config failed.\n");
++ }
++ }
++}
+ /* called during probe() after chip reset completes */
+ static int ehci_fsl_setup(struct usb_hcd *hcd)
+ {
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
++ struct fsl_usb2_platform_data *pdata;
++
++ pdata = hcd->self.controller->platform_data;
++
++ ehci->big_endian_desc = pdata->big_endian_desc;
++ ehci->big_endian_mmio = pdata->big_endian_mmio;
++ /*printk("ehci->big_endian_desc :%d ehci->big_endian_mmio:%d\n",ehci->big_endian_desc,ehci->big_endian_mmio );*/
+
++
+ /* EHCI registers start at offset 0x100 */
+ ehci->caps = hcd->regs + 0x100;
++ DBGMsg("ehci->caps->hc_capbase: 0x%x\n", ehci->caps->hc_capbase);
++
+ ehci->regs = hcd->regs + 0x100 +
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ dbg_hcs_params(ehci, "reset");
+@@ -264,26 +397,58 @@
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+-
++ /*printk("%s() line:%d\n",__func__,__LINE__);*/
+ retval = ehci_halt(ehci);
++ /*
+ if (retval)
+ return retval;
+-
++ */
++ /*printk("%s() line:%d\n",__func__,__LINE__);*/
+ /* data structure init */
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+-
++ /*printk("%s() line:%d\n",__func__,__LINE__);*/
+ hcd->has_tt = 1;
+-
+ ehci->sbrn = 0x20;
+
+- ehci_reset(ehci);
+-
+- retval = ehci_fsl_reinit(ehci);
++ retval = ehci_reset(ehci);
++ retval = ehci_fsl_reinit(ehci);
+ return retval;
+ }
+
++#define PER_CM_BURST 0x0101
++#define POST_CM_BURST 0x0808
++extern void ahb_lock(void);
++extern void ahb_unlock(void);
++
++#if 0
++/*
++ * Called before control messages.
++ * Lower the BURSTSIZE to avoid USB bus hangs
++ */
++static void ehci_fsl_pre_cm_hook(struct usb_hcd *hcd)
++{
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++
++ ahb_lock();
++ ehci_writel(ehci, PER_CM_BURST, hcd->regs + FSL_SOC_USB_BURSTSIZE);
++
++}
++
++/*
++ * Called after control messages.
++ * Restore the BURSTSIZE register so that bulk I/O works
++ */
++static void ehci_fsl_post_cm_hook(struct usb_hcd *hcd)
++{
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++
++ ehci_writel(ehci, POST_CM_BURST, hcd->regs + FSL_SOC_USB_BURSTSIZE);
++ ahb_unlock();
++}
++#endif
++
+ static const struct hc_driver ehci_fsl_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Freescale On-Chip EHCI Host Controller",
+@@ -293,7 +458,7 @@
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+- .flags = HCD_USB2,
++ .flags = HCD_USB2 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+@@ -325,9 +490,19 @@
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+ };
++#ifndef CONFIG_FS_ENET_MPC5125_FEC2
++extern void mpc5125_fec2_usb_io_init(unsigned char isusb);
++#endif
+
+ static int ehci_fsl_drv_probe(struct platform_device *pdev)
+ {
++#ifndef CONFIG_FS_ENET_MPC5125_FEC2
++ mpc5125_fec2_usb_io_init(1);
++#else
++ printk(KERN_ERR"The kernel configed fec2,so can't use usb1\n");
++ return -EIO;
++#endif
++
+ if (usb_disabled())
+ return -ENODEV;
+
+@@ -344,12 +519,172 @@
+ return 0;
+ }
+
++
++#ifdef CONFIG_PM
++/* suspend/resume, section 4.3 */
++
++/* These routines rely on the bus (pci, platform, etc)
++ * to handle powerdown and wakeup, and currently also on
++ * transceivers that don't need any software attention to set up
++ * the right sort of wakeup.
++ *
++ * They're also used for turning on/off the port when doing OTG.
++ */
++static int ehci_fsl_drv_suspend(struct platform_device *pdev,
++ pm_message_t message)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ u32 tmp;
++ struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
++
++#ifdef DEBUG
++ u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE);
++ mode &= USBMODE_CM_MASK;
++ tmp = ehci_readl(ehci, hcd->regs + 0x140); /* usbcmd */
++
++ printk(KERN_DEBUG "%s('%s'): suspend=%d already_suspended=%d "
++ "mode=%d usbcmd %08x\n", __func__, pdata->name,
++ pdata->suspended, pdata->already_suspended, mode, tmp);
++#endif
++
++ /*
++ * If the controller is already suspended, then this must be a
++ * PM suspend. Remember this fact, so that we will leave the
++ * controller suspended at PM resume time.
++ */
++ if (pdata->suspended) {
++ pr_debug("%s: already suspended, leaving early\n", __func__);
++ pdata->already_suspended = 1;
++ return 0;
++ }
++
++ pr_debug("%s: suspending...\n", __func__);
++
++ printk(KERN_INFO "USB Host suspended\n");
++
++ hcd->state = HC_STATE_SUSPENDED;
++ pdev->dev.power.power_state = PMSG_SUSPEND;
++
++ if (hcd->driver->pci_suspend)
++ return hcd->driver->pci_suspend(hcd, message);
++
++ /* ignore non-host interrupts */
++ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
++
++ /* stop the controller */
++ tmp = ehci_readl(ehci, &ehci->regs->command);
++ tmp &= ~CMD_RUN;
++ ehci_writel(ehci, tmp, &ehci->regs->command);
++
++ /* save EHCI registers */
++ pdata->pm_command = ehci_readl(ehci, &ehci->regs->command);
++ pdata->pm_command &= ~CMD_RUN;
++ pdata->pm_status = ehci_readl(ehci, &ehci->regs->status);
++ pdata->pm_intr_enable = ehci_readl(ehci, &ehci->regs->intr_enable);
++ pdata->pm_frame_index = ehci_readl(ehci, &ehci->regs->frame_index);
++ pdata->pm_segment = ehci_readl(ehci, &ehci->regs->segment);
++ pdata->pm_frame_list = ehci_readl(ehci, &ehci->regs->frame_list);
++ pdata->pm_async_next = ehci_readl(ehci, &ehci->regs->async_next);
++ pdata->pm_configured_flag =
++ ehci_readl(ehci, &ehci->regs->configured_flag);
++ pdata->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
++
++ /* clear the W1C bits */
++ pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS);
++
++ pdata->suspended = 1;
++
++ /* clear PP to cut power to the port */
++ tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
++ tmp &= ~PORT_POWER;
++ ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
++
++ return 0;
++}
++
++static int ehci_fsl_drv_resume(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ u32 tmp;
++ struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
++
++ printk(KERN_INFO "USB Host resumed\n");
++
++ pr_debug("%s('%s'): suspend=%d already_suspended=%d\n", __func__,
++ pdata->name, pdata->suspended, pdata->already_suspended);
++
++ /*
++ * If the controller was already suspended at suspend time,
++ * then don't resume it now.
++ */
++ if (pdata->already_suspended) {
++ pr_debug("already suspended, leaving early\n");
++ pdata->already_suspended = 0;
++ return 0;
++ }
++
++ if (!pdata->suspended) {
++ pr_debug("not suspended, leaving early\n");
++ return 0;
++ }
++
++ pdata->suspended = 0;
++
++ pr_debug("%s resuming...\n", __func__);
++
++ /* set host mode */
++ tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
++ ehci_writel(ehci, tmp, hcd->regs + FSL_SOC_USB_USBMODE);
++
++ /*
++ * set SBUSCFG:AHBBRST so that control msgs don't
++ * fail when doing heavy PATA writes.
++ */
++ ehci_writel(ehci, SBUSCFG_INCR8, hcd->regs + FSL_SOC_USB_SBUSCFG);
++
++ ehci_writel(ehci, USBGENCTRL_PPP | USBGENCTRL_PFP, hcd->regs + FSL_SOC_USB_USBGENCTRL);
++ ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE, hcd->regs + FSL_SOC_USB_ISIPHYCTRL);
++
++ /* restore EHCI registers */
++ ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
++ ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);
++ ehci_writel(ehci, pdata->pm_frame_index, &ehci->regs->frame_index);
++ ehci_writel(ehci, pdata->pm_segment, &ehci->regs->segment);
++ ehci_writel(ehci, pdata->pm_frame_list, &ehci->regs->frame_list);
++ ehci_writel(ehci, pdata->pm_async_next, &ehci->regs->async_next);
++ ehci_writel(ehci, pdata->pm_configured_flag,
++ &ehci->regs->configured_flag);
++ ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
++
++ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
++ hcd->state = HC_STATE_RUNNING;
++ pdev->dev.power.power_state = PMSG_ON;
++
++ tmp = ehci_readl(ehci, &ehci->regs->command);
++ tmp |= CMD_RUN;
++ ehci_writel(ehci, tmp, &ehci->regs->command);
++
++ usb_hcd_resume_root_hub(hcd);
++#ifdef CONFIG_MPC5125_TWR
++ usb3320_reset(hcd);
++#endif
++
++ return 0;
++}
++#endif /* CONFIG_USB_OTG */
++
+ MODULE_ALIAS("platform:fsl-ehci");
+
+ static struct platform_driver ehci_fsl_driver = {
+ .probe = ehci_fsl_drv_probe,
+ .remove = ehci_fsl_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
++#ifdef CONFIG_PM
++ .suspend = ehci_fsl_drv_suspend,
++ .resume = ehci_fsl_drv_resume,
++#endif
+ .driver = {
+ .name = "fsl-ehci",
+ },
+diff -Naur linux-2.6.29/drivers/usb/host/ehci-fsl.h linux-2.6.29-v2010041601/drivers/usb/host/ehci-fsl.h
+--- linux-2.6.29/drivers/usb/host/ehci-fsl.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/usb/host/ehci-fsl.h 2010-04-13 20:23:26.000000000 +0200
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 2005 freescale semiconductor
++/* Copyright (C) 2005-2009 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * This program is free software; you can redistribute it and/or modify it
+@@ -19,6 +19,8 @@
+ #define _EHCI_FSL_H
+
+ /* offsets for the non-ehci registers in the FSL SOC USB controller */
++#define FSL_SOC_USB_SBUSCFG 0x90
++#define FSL_SOC_USB_BURSTSIZE 0x160
+ #define FSL_SOC_USB_ULPIVP 0x170
+ #define FSL_SOC_USB_PORTSC1 0x184
+ #define PORT_PTS_MSK (3<<30)
+@@ -26,8 +28,22 @@
+ #define PORT_PTS_ULPI (2<<30)
+ #define PORT_PTS_SERIAL (3<<30)
+ #define PORT_PTS_PTW (1<<28)
++#define PORT_PTS_PHCD (1<<23)
+ #define FSL_SOC_USB_PORTSC2 0x188
++#define FSL_SOC_USB_OTGSC 0x1a4
++#define OTGSC_ID (1 << 8) /* 1 == B device */
+ #define FSL_SOC_USB_USBMODE 0x1a8
++#define USBMODE_CM_MASK (3 << 0) /* controller mode mask */
++#define USBMODE_CM_HOST (3 << 0) /* controller mode: host */
++#define USBMODE_ES (1 << 2) /* (Big) Endian Select */
++
++#define FSL_SOC_USB_USBGENCTRL 0x200
++#define USBGENCTRL_PPP (1 << 3)
++#define USBGENCTRL_PFP (1 << 2)
++#define FSL_SOC_USB_ISIPHYCTRL 0x204
++#define ISIPHYCTRL_PXE (1)
++#define ISIPHYCTRL_PHYE (1 << 4)
++
+ #define FSL_SOC_USB_SNOOP1 0x400 /* NOTE: big-endian */
+ #define FSL_SOC_USB_SNOOP2 0x404 /* NOTE: big-endian */
+ #define FSL_SOC_USB_AGECNTTHRSH 0x408 /* NOTE: big-endian */
+@@ -35,4 +51,11 @@
+ #define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */
+ #define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */
+ #define SNOOP_SIZE_2GB 0x1e
++
++#ifdef CONFIG_ARCH_MXC
++#include <asm/arch/fsl_usb.h>
++#elif CONFIG_PPC32
++#include <asm/fsl_usb.h>
++#endif
++
+ #endif /* _EHCI_FSL_H */
+diff -Naur linux-2.6.29/drivers/usb/host/ehci.h linux-2.6.29-v2010041601/drivers/usb/host/ehci.h
+--- linux-2.6.29/drivers/usb/host/ehci.h 2011-02-27 13:59:00.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/usb/host/ehci.h 2010-04-13 20:23:26.000000000 +0200
+@@ -742,5 +742,6 @@
+ #endif /* DEBUG */
+
+ /*-------------------------------------------------------------------------*/
++#define SBUSCFG_INCR8 0x02 /* INCR8, specified */
+
+ #endif /* __LINUX_EHCI_HCD_H */
+diff -Naur linux-2.6.29/drivers/usb/host/ehci-hcd.c linux-2.6.29-v2010041601/drivers/usb/host/ehci-hcd.c
+--- linux-2.6.29/drivers/usb/host/ehci-hcd.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/usb/host/ehci-hcd.c 2010-04-13 20:23:26.000000000 +0200
+@@ -178,7 +178,9 @@
+
+ return error;
+ }
+-
++#ifdef CONFIG_PPC_MPC512x
++static void ehci_fsl_sbusconfig(struct ehci_hcd *ehci);
++#endif
+ /* put TDI/ARC silicon into EHCI mode */
+ static void tdi_reset (struct ehci_hcd *ehci)
+ {
+@@ -194,7 +196,13 @@
+ */
+ if (ehci_big_endian_mmio(ehci))
+ tmp |= USBMODE_BE;
++#ifdef CONFIG_PPC_MPC512x /* must set USBMODE:ES for 5121 */
++ tmp |= USBMODE_BE;
++#endif
+ ehci_writel(ehci, tmp, reg_ptr);
++#ifdef CONFIG_PPC_MPC512x
++ ehci_fsl_sbusconfig(ehci);
++#endif
+ }
+
+ /* reset a non-running (STS_HALT == 1) controller */
+@@ -259,6 +267,23 @@
+
+ /*-------------------------------------------------------------------------*/
+
++static void ehci_watchdog(unsigned long param)
++{
++ struct ehci_hcd *ehci = (struct ehci_hcd *) param;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ehci->lock, flags);
++
++ /* stop async processing after it's idled a bit */
++ if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
++ start_unlink_async (ehci, ehci->async);
++
++ /* ehci could run by timer, without IRQs ... */
++ ehci_work (ehci);
++
++ spin_unlock_irqrestore (&ehci->lock, flags);
++}
++
+ static void ehci_iaa_watchdog(unsigned long param)
+ {
+ struct ehci_hcd *ehci = (struct ehci_hcd *) param;
+@@ -307,23 +332,6 @@
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ }
+
+-static void ehci_watchdog(unsigned long param)
+-{
+- struct ehci_hcd *ehci = (struct ehci_hcd *) param;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&ehci->lock, flags);
+-
+- /* stop async processing after it's idled a bit */
+- if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
+- start_unlink_async (ehci, ehci->async);
+-
+- /* ehci could run by timer, without IRQs ... */
+- ehci_work (ehci);
+-
+- spin_unlock_irqrestore (&ehci->lock, flags);
+-}
+-
+ /* On some systems, leaving remote wakeup enabled prevents system shutdown.
+ * The firmware seems to think that powering off is a wakeup event!
+ * This routine turns off remote wakeup and everything else, on all ports.
+diff -Naur linux-2.6.29/drivers/video/fbmem.c linux-2.6.29-v2010041601/drivers/video/fbmem.c
+--- linux-2.6.29/drivers/video/fbmem.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/video/fbmem.c 2010-04-13 20:23:26.000000000 +0200
+@@ -419,7 +419,7 @@
+ u32 *palette = NULL, *saved_pseudo_palette = NULL;
+ unsigned char *logo_new = NULL, *logo_rotate = NULL;
+ struct fb_image image;
+-
++ struct fb_var_screeninfo *var=&info->var;
+ /* Return if the frame buffer is not mapped or suspended */
+ if (logo == NULL || info->state != FBINFO_STATE_RUNNING ||
+ info->flags & FBINFO_MODULE)
+diff -Naur linux-2.6.29/drivers/video/fsl-diu-fb.c linux-2.6.29-v2010041601/drivers/video/fsl-diu-fb.c
+--- linux-2.6.29/drivers/video/fsl-diu-fb.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/video/fsl-diu-fb.c 2010-04-13 20:23:26.000000000 +0200
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright (C) 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale DIU Frame Buffer device driver
+ *
+@@ -7,6 +7,7 @@
+ * Paul Widmer <paul.widmer@freescale.com>
+ * Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
+ * York Sun <yorksun@freescale.com>
++ * Copyright (C) Freescale Semicondutor, Inc. 2007. All rights reserved.
+ *
+ * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
+ *
+@@ -28,179 +29,50 @@
+ #include <linux/platform_device.h>
+ #include <linux/interrupt.h>
+ #include <linux/clk.h>
+-#include <linux/uaccess.h>
+-#include <linux/vmalloc.h>
++#include <asm/uaccess.h>
+
+-#include <linux/of_platform.h>
++#include <asm/of_platform.h>
+
+ #include <sysdev/fsl_soc.h>
++#undef DEBUG
+ #include "fsl-diu-fb.h"
+
+-/*
+- * These parameters give default parameters
+- * for video output 1024x768,
+- * FIXME - change timing to proper amounts
+- * hsync 31.5kHz, vsync 60Hz
+- */
+-static struct fb_videomode __devinitdata fsl_diu_default_mode = {
+- .refresh = 60,
+- .xres = 1024,
+- .yres = 768,
+- .pixclock = 15385,
+- .left_margin = 160,
+- .right_margin = 24,
+- .upper_margin = 29,
+- .lower_margin = 3,
+- .hsync_len = 136,
+- .vsync_len = 6,
+- .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+- .vmode = FB_VMODE_NONINTERLACED
+-};
+-
+-static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
+- {
+- .name = "1024x768-60",
+- .refresh = 60,
+- .xres = 1024,
+- .yres = 768,
+- .pixclock = 15385,
+- .left_margin = 160,
+- .right_margin = 24,
+- .upper_margin = 29,
+- .lower_margin = 3,
+- .hsync_len = 136,
+- .vsync_len = 6,
+- .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+- .vmode = FB_VMODE_NONINTERLACED
+- },
+- {
+- .name = "1024x768-70",
+- .refresh = 70,
+- .xres = 1024,
+- .yres = 768,
+- .pixclock = 16886,
+- .left_margin = 3,
+- .right_margin = 3,
+- .upper_margin = 2,
+- .lower_margin = 2,
+- .hsync_len = 40,
+- .vsync_len = 18,
+- .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+- .vmode = FB_VMODE_NONINTERLACED
+- },
+- {
+- .name = "1024x768-75",
+- .refresh = 75,
+- .xres = 1024,
+- .yres = 768,
+- .pixclock = 15009,
+- .left_margin = 3,
+- .right_margin = 3,
+- .upper_margin = 2,
+- .lower_margin = 2,
+- .hsync_len = 80,
+- .vsync_len = 32,
+- .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+- .vmode = FB_VMODE_NONINTERLACED
+- },
+- {
+- .name = "1280x1024-60",
+- .refresh = 60,
+- .xres = 1280,
+- .yres = 1024,
+- .pixclock = 9375,
+- .left_margin = 38,
+- .right_margin = 128,
+- .upper_margin = 2,
+- .lower_margin = 7,
+- .hsync_len = 216,
+- .vsync_len = 37,
+- .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+- .vmode = FB_VMODE_NONINTERLACED
+- },
+- {
+- .name = "1280x1024-70",
+- .refresh = 70,
+- .xres = 1280,
+- .yres = 1024,
+- .pixclock = 9380,
+- .left_margin = 6,
+- .right_margin = 6,
+- .upper_margin = 4,
+- .lower_margin = 4,
+- .hsync_len = 60,
+- .vsync_len = 94,
+- .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+- .vmode = FB_VMODE_NONINTERLACED
+- },
+- {
+- .name = "1280x1024-75",
+- .refresh = 75,
+- .xres = 1280,
+- .yres = 1024,
+- .pixclock = 9380,
+- .left_margin = 6,
+- .right_margin = 6,
+- .upper_margin = 4,
+- .lower_margin = 4,
+- .hsync_len = 60,
+- .vsync_len = 15,
+- .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+- .vmode = FB_VMODE_NONINTERLACED
+- },
+- {
+- .name = "320x240", /* for AOI only */
+- .refresh = 60,
+- .xres = 320,
+- .yres = 240,
+- .pixclock = 15385,
+- .left_margin = 0,
+- .right_margin = 0,
+- .upper_margin = 0,
+- .lower_margin = 0,
+- .hsync_len = 0,
+- .vsync_len = 0,
+- .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+- .vmode = FB_VMODE_NONINTERLACED
+- },
+- {
+- .name = "1280x480-60",
+- .refresh = 60,
+- .xres = 1280,
+- .yres = 480,
+- .pixclock = 18939,
+- .left_margin = 353,
+- .right_margin = 47,
+- .upper_margin = 39,
+- .lower_margin = 4,
+- .hsync_len = 8,
+- .vsync_len = 2,
+- .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+- .vmode = FB_VMODE_NONINTERLACED
+- },
+-};
+-
++static int irq;
++#if(PANEL_TYPE_SELECT==PANEL_TYPE_DEFAULT)
+ static char *fb_mode = "1024x768-32@60";
+-static unsigned long default_bpp = 32;
+-static int monitor_port;
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_800x600_42)
++static char *fb_mode = "800x600-32@42";
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_640x480_60)
++static char *fb_mode = "640x480-32@60";
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_720x576_60)
++static char *fb_mode = "720x576-32@50";
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_1024x768_26)
++static char *fb_mode = "1024x768-32@26";
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_720x480_60)
++static char *fb_mode = "720x480-32@60";
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_1280x720_50)
++static char *fb_mode = "1280x720-32@50";
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_1280x720_60)
++static char *fb_mode = "1280x720-32@60";
++#else
++#panel select failed
++#endif
++static int fb_enabled = 0;
++static unsigned long default_bpp = 8;
++static ATOMIC_NOTIFIER_HEAD(fsl_diu_notifier_list);
++static int monitor_port = 0;
++static struct diu_ad * dummy_ad;
++void * dummy_aoi_virt;
+
+ #if defined(CONFIG_NOT_COHERENT_CACHE)
+-static u8 *coherence_data;
+-static size_t coherence_data_size;
+-static unsigned int d_cache_line_size;
++unsigned int *coherence_data;
++dma_addr_t *coherence_data_phy;
+ #endif
+
+-static DEFINE_SPINLOCK(diu_lock);
+-
+-struct fsl_diu_data {
+- struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1];
+- /*FSL_AOI_NUM has one dummy AOI */
+- struct device_attribute dev_attr;
+- struct diu_ad *dummy_ad;
+- void *dummy_aoi_virt;
+- unsigned int irq;
+- int fb_enabled;
+- int monitor_port;
++struct fsl_diu_vsync {
++ wait_queue_head_t wait;
++ volatile unsigned int count;
++ unsigned long addr;
+ };
+
+ struct mfb_info {
+@@ -209,19 +81,75 @@
+ char *id;
+ int registered;
+ int blank;
+- unsigned long pseudo_palette[16];
++ unsigned long pseudo_palette[256];
+ struct diu_ad *ad;
+ int cursor_reset;
+ unsigned char g_alpha;
+ unsigned int count;
+ int x_aoi_d; /* aoi display x offset to physical screen */
+ int y_aoi_d; /* aoi display y offset to physical screen */
+- struct fsl_diu_data *parent;
++ struct fsl_diu_vsync vsync;
+ };
+
++/* FIXME: Change static declarations and rearrange functions */
++static int fsl_diu_open(struct fb_info *info, int user);
++static int fsl_diu_release(struct fb_info *info, int user);
++static int fsl_diu_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
++static int fsl_diu_set_par(struct fb_info *info);
++static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green,
++ unsigned blue, unsigned transp,
++ struct fb_info *info);
++static int fsl_diu_pan_display(struct fb_var_screeninfo *var,
++ struct fb_info *info);
++static int fsl_diu_blank(int blank_mode, struct fb_info *info);
++static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
++ unsigned long arg);
++static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor);
++
++int __init fsl_diu_init(void);
++void __exit fsl_diu_exit(void);
++#ifndef MODULE
++static int __init fsl_diu_setup(char *);
++#endif
++
++static int init_fbinfo(struct fb_info *info,
++ struct platform_device *pdev);
++static int install_fb(struct fb_info *info,
++ struct platform_device *pdev);
++static void __exit uninstall_fb(struct fb_info *info);
++static int map_video_memory(struct fb_info *info);
++static void unmap_video_memory(struct fb_info *info);
++static void set_fix(struct fb_info *info);
++static void enable_lcdc(struct fb_info *info);
++static void disable_lcdc(struct fb_info *info);
++static void update_lcdc(struct fb_info *info);
++static void request_irq_local(void);
++static void free_irq_local(void);
++static int fsl_diu_enable_panel(struct fb_info *info);
++static int fsl_diu_disable_panel(struct fb_info *info);
++static int fsl_diu_probe(struct platform_device *pdev);
++static int wait_for_vsync(void);
+
+-static struct mfb_info mfb_template[] = {
+- { /* AOI 0 for plane 0 */
++#ifdef CONFIG_PM
++static int fsl_diu_suspend(struct platform_device *pdev, pm_message_t state);
++static int fsl_diu_resume(struct platform_device *pdev);
++#else
++#define fsl_diu_suspend 0
++#define fsl_diu_resume 0
++#endif
++
++extern unsigned int platform_get_pixel_format(unsigned int bits_per_pixel,
++ int monitor_port, char byte_flip);
++extern void platform_set_gamma_table(int monitor_port, char *gamma_table_base);
++extern void platform_set_pixel_clock(unsigned int pixclock);
++extern ssize_t platform_show_monitor_port(int monitor_port, char * buf);
++extern int platform_set_monitor_port(int val);
++extern int platform_set_sysfs_monitor_port(int val);
++
++/* Driver data */
++static int hwcursor = 1;
++
++struct mfb_info mfbi_p0 = {
+ .index = 0,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel0",
+@@ -229,8 +157,9 @@
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 0,
+- },
+- { /* AOI 0 for plane 1 */
++};
++
++struct mfb_info mfbi_p1_0 = {
+ .index = 1,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel1 AOI0",
+@@ -239,8 +168,9 @@
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 0,
+- },
+- { /* AOI 1 for plane 1 */
++};
++
++struct mfb_info mfbi_p1_1 = {
+ .index = 2,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel1 AOI1",
+@@ -249,8 +179,9 @@
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 480,
+- },
+- { /* AOI 0 for plane 2 */
++};
++
++struct mfb_info mfbi_p2_0 = {
+ .index = 3,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel2 AOI0",
+@@ -259,8 +190,9 @@
+ .count = 0,
+ .x_aoi_d = 640,
+ .y_aoi_d = 0,
+- },
+- { /* AOI 1 for plane 2 */
++};
++
++struct mfb_info mfbi_p2_1 = {
+ .index = 4,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel2 AOI1",
+@@ -269,272 +201,117 @@
+ .count = 0,
+ .x_aoi_d = 640,
+ .y_aoi_d = 480,
+- },
+ };
+
+ static struct diu_hw dr = {
+ .mode = MFB_MODE1,
+- .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock),
++ .reg_lock = SPIN_LOCK_UNLOCKED,
+ };
+
+-static struct diu_pool pool;
++struct diu_pool pool;
+
+-/**
+- * fsl_diu_alloc - allocate memory for the DIU
+- * @size: number of bytes to allocate
+- * @param: returned physical address of memory
+- *
+- * This function allocates a physically-contiguous block of memory.
+- */
+-static void *fsl_diu_alloc(size_t size, phys_addr_t *phys)
+-{
+- void *virt;
++static struct fb_info fsl_diu_info[] = {
++ {.par = &mfbi_p0},
++ {.par = &mfbi_p1_0},
++ {.par = &mfbi_p1_1},
++ {.par = &mfbi_p2_0},
++ {.par = &mfbi_p2_1},
++};
+
+- pr_debug("size=%zu\n", size);
++static struct platform_driver fsl_diu_driver = {
++ .driver = {
++ .name = "fsl_diu",
++ .owner = THIS_MODULE,
++ .bus = &platform_bus_type,
++ },
++ .probe = fsl_diu_probe,
++ .suspend = fsl_diu_suspend,
++ .resume = fsl_diu_resume,
++};
+
+- virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO);
+- if (virt) {
+- *phys = virt_to_phys(virt);
+- pr_debug("virt=%p phys=%llx\n", virt,
+- (unsigned long long)*phys);
+- }
++static struct fb_ops fsl_diu_ops = {
++ .owner = THIS_MODULE,
++ .fb_check_var = fsl_diu_check_var,
++ .fb_set_par = fsl_diu_set_par,
++ .fb_setcolreg = fsl_diu_setcolreg,
++ .fb_blank = fsl_diu_blank,
++ .fb_pan_display = fsl_diu_pan_display,
++ .fb_fillrect = cfb_fillrect,
++ .fb_cursor = fsl_diu_cursor,
++ .fb_copyarea = cfb_copyarea,
++ .fb_imageblit = cfb_imageblit,
++ .fb_ioctl = fsl_diu_ioctl,
++ .fb_open = fsl_diu_open,
++ .fb_release = fsl_diu_release,
++};
++
++static void write_reg(u32 *reg, u32 value)
++{
++ unsigned long flag;
+
+- return virt;
++ spin_lock_irqsave(&dr.reg_lock, flag);
++ *reg = value;
++ spin_unlock_irqrestore(&dr.reg_lock, flag);
+ }
+
+-/**
+- * fsl_diu_free - release DIU memory
+- * @virt: pointer returned by fsl_diu_alloc()
+- * @size: number of bytes allocated by fsl_diu_alloc()
+- *
+- * This function releases memory allocated by fsl_diu_alloc().
+- */
+-static void fsl_diu_free(void *virt, size_t size)
++static u32 read_reg(u32 *reg)
+ {
+- pr_debug("virt=%p size=%zu\n", virt, size);
++ u32 value;
++ unsigned long flag;
+
+- if (virt && size)
+- free_pages_exact(virt, size);
++ spin_lock_irqsave(&dr.reg_lock, flag);
++ value = *reg;
++ spin_unlock_irqrestore(&dr.reg_lock, flag);
++ return value;
+ }
+
+-static int fsl_diu_enable_panel(struct fb_info *info)
++/* Workaround for failed writing desc register of planes
++ */
++void write_reg_wa(u32 *reg, u32 val)
+ {
+- struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
+- struct diu *hw = dr.diu_reg;
+- struct diu_ad *ad = mfbi->ad;
+- struct fsl_diu_data *machine_data = mfbi->parent;
+- int res = 0;
+-
+- pr_debug("enable_panel index %d\n", mfbi->index);
+- if (mfbi->type != MFB_TYPE_OFF) {
+- switch (mfbi->index) {
+- case 0: /* plane 0 */
+- if (hw->desc[0] != ad->paddr)
+- out_be32(&hw->desc[0], ad->paddr);
+- break;
+- case 1: /* plane 1 AOI 0 */
+- cmfbi = machine_data->fsl_diu_info[2]->par;
+- if (hw->desc[1] != ad->paddr) { /* AOI0 closed */
+- if (cmfbi->count > 0) /* AOI1 open */
+- ad->next_ad =
+- cpu_to_le32(cmfbi->ad->paddr);
+- else
+- ad->next_ad = 0;
+- out_be32(&hw->desc[1], ad->paddr);
+- }
+- break;
+- case 3: /* plane 2 AOI 0 */
+- cmfbi = machine_data->fsl_diu_info[4]->par;
+- if (hw->desc[2] != ad->paddr) { /* AOI0 closed */
+- if (cmfbi->count > 0) /* AOI1 open */
+- ad->next_ad =
+- cpu_to_le32(cmfbi->ad->paddr);
+- else
+- ad->next_ad = 0;
+- out_be32(&hw->desc[2], ad->paddr);
+- }
+- break;
+- case 2: /* plane 1 AOI 1 */
+- pmfbi = machine_data->fsl_diu_info[1]->par;
+- ad->next_ad = 0;
+- if (hw->desc[1] == machine_data->dummy_ad->paddr)
+- out_be32(&hw->desc[1], ad->paddr);
+- else /* AOI0 open */
+- pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
+- break;
+- case 4: /* plane 2 AOI 1 */
+- pmfbi = machine_data->fsl_diu_info[3]->par;
+- ad->next_ad = 0;
+- if (hw->desc[2] == machine_data->dummy_ad->paddr)
+- out_be32(&hw->desc[2], ad->paddr);
+- else /* AOI0 was open */
+- pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
+- break;
+- default:
+- res = -EINVAL;
+- break;
+- }
+- } else
+- res = -EINVAL;
+- return res;
++ do {
++ write_reg(reg, val);
++ } while (*reg != val);
+ }
+
+-static int fsl_diu_disable_panel(struct fb_info *info)
++/* turn on fb if count == 1
++ */
++static int fsl_diu_open(struct fb_info *info, int user)
+ {
+- struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
+- struct diu *hw = dr.diu_reg;
+- struct diu_ad *ad = mfbi->ad;
+- struct fsl_diu_data *machine_data = mfbi->parent;
++ struct mfb_info *mfbi = (struct mfb_info *)info->par;
+ int res = 0;
+
+- switch (mfbi->index) {
+- case 0: /* plane 0 */
+- if (hw->desc[0] != machine_data->dummy_ad->paddr)
+- out_be32(&hw->desc[0],
+- machine_data->dummy_ad->paddr);
+- break;
+- case 1: /* plane 1 AOI 0 */
+- cmfbi = machine_data->fsl_diu_info[2]->par;
+- if (cmfbi->count > 0) /* AOI1 is open */
+- out_be32(&hw->desc[1], cmfbi->ad->paddr);
+- /* move AOI1 to the first */
+- else /* AOI1 was closed */
+- out_be32(&hw->desc[1],
+- machine_data->dummy_ad->paddr);
+- /* close AOI 0 */
+- break;
+- case 3: /* plane 2 AOI 0 */
+- cmfbi = machine_data->fsl_diu_info[4]->par;
+- if (cmfbi->count > 0) /* AOI1 is open */
+- out_be32(&hw->desc[2], cmfbi->ad->paddr);
+- /* move AOI1 to the first */
+- else /* AOI1 was closed */
+- out_be32(&hw->desc[2],
+- machine_data->dummy_ad->paddr);
+- /* close AOI 0 */
+- break;
+- case 2: /* plane 1 AOI 1 */
+- pmfbi = machine_data->fsl_diu_info[1]->par;
+- if (hw->desc[1] != ad->paddr) {
+- /* AOI1 is not the first in the chain */
+- if (pmfbi->count > 0)
+- /* AOI0 is open, must be the first */
+- pmfbi->ad->next_ad = 0;
+- } else /* AOI1 is the first in the chain */
+- out_be32(&hw->desc[1], machine_data->dummy_ad->paddr);
+- /* close AOI 1 */
+- break;
+- case 4: /* plane 2 AOI 1 */
+- pmfbi = machine_data->fsl_diu_info[3]->par;
+- if (hw->desc[2] != ad->paddr) {
+- /* AOI1 is not the first in the chain */
+- if (pmfbi->count > 0)
+- /* AOI0 is open, must be the first */
+- pmfbi->ad->next_ad = 0;
+- } else /* AOI1 is the first in the chain */
+- out_be32(&hw->desc[2], machine_data->dummy_ad->paddr);
+- /* close AOI 1 */
+- break;
+- default:
+- res = -EINVAL;
+- break;
++ mfbi->count++;
++ if (mfbi->count == 1) {
++ DPRINTK("open plane index %d\n",mfbi->index);
++ fsl_diu_check_var(&info->var,info);
++ fsl_diu_set_par(info);
++ res = fsl_diu_enable_panel(info);
++ if (res < 0)
++ mfbi->count--;
+ }
+
+ return res;
+ }
+
+-static void enable_lcdc(struct fb_info *info)
++/* turn off fb if count == 0
++ */
++static int fsl_diu_release(struct fb_info *info, int user)
+ {
+- struct diu *hw = dr.diu_reg;
+- struct mfb_info *mfbi = info->par;
+- struct fsl_diu_data *machine_data = mfbi->parent;
++ struct mfb_info *mfbi = (struct mfb_info *)info->par;
++ int res = 0;
+
+- if (!machine_data->fb_enabled) {
+- out_be32(&hw->diu_mode, dr.mode);
+- machine_data->fb_enabled++;
++ mfbi->count--;
++ if (mfbi->count == 0) {
++ DPRINTK("release plane index %d\n",mfbi->index);
++ res = fsl_diu_disable_panel(info);
++ if (res < 0)
++ mfbi->count++;
+ }
+-}
+
+-static void disable_lcdc(struct fb_info *info)
+-{
+- struct diu *hw = dr.diu_reg;
+- struct mfb_info *mfbi = info->par;
+- struct fsl_diu_data *machine_data = mfbi->parent;
+-
+- if (machine_data->fb_enabled) {
+- out_be32(&hw->diu_mode, 0);
+- machine_data->fb_enabled = 0;
+- }
++ return res;
+ }
+
+-static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
+- struct fb_info *info)
+-{
+- struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par;
+- struct fsl_diu_data *machine_data = mfbi->parent;
+- int available_height, upper_aoi_bottom, index = mfbi->index;
+- int lower_aoi_is_open, upper_aoi_is_open;
+- __u32 base_plane_width, base_plane_height, upper_aoi_height;
+-
+- base_plane_width = machine_data->fsl_diu_info[0]->var.xres;
+- base_plane_height = machine_data->fsl_diu_info[0]->var.yres;
+-
+- if (mfbi->x_aoi_d < 0)
+- mfbi->x_aoi_d = 0;
+- if (mfbi->y_aoi_d < 0)
+- mfbi->y_aoi_d = 0;
+- switch (index) {
+- case 0:
+- if (mfbi->x_aoi_d != 0)
+- mfbi->x_aoi_d = 0;
+- if (mfbi->y_aoi_d != 0)
+- mfbi->y_aoi_d = 0;
+- break;
+- case 1: /* AOI 0 */
+- case 3:
+- lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par;
+- lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0;
+- if (var->xres > base_plane_width)
+- var->xres = base_plane_width;
+- if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
+- mfbi->x_aoi_d = base_plane_width - var->xres;
+-
+- if (lower_aoi_is_open)
+- available_height = lower_aoi_mfbi->y_aoi_d;
+- else
+- available_height = base_plane_height;
+- if (var->yres > available_height)
+- var->yres = available_height;
+- if ((mfbi->y_aoi_d + var->yres) > available_height)
+- mfbi->y_aoi_d = available_height - var->yres;
+- break;
+- case 2: /* AOI 1 */
+- case 4:
+- upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par;
+- upper_aoi_height =
+- machine_data->fsl_diu_info[index-1]->var.yres;
+- upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height;
+- upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0;
+- if (var->xres > base_plane_width)
+- var->xres = base_plane_width;
+- if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
+- mfbi->x_aoi_d = base_plane_width - var->xres;
+- if (mfbi->y_aoi_d < 0)
+- mfbi->y_aoi_d = 0;
+- if (upper_aoi_is_open) {
+- if (mfbi->y_aoi_d < upper_aoi_bottom)
+- mfbi->y_aoi_d = upper_aoi_bottom;
+- available_height = base_plane_height
+- - upper_aoi_bottom;
+- } else
+- available_height = base_plane_height;
+- if (var->yres > available_height)
+- var->yres = available_height;
+- if ((mfbi->y_aoi_d + var->yres) > base_plane_height)
+- mfbi->y_aoi_d = base_plane_height - var->yres;
+- break;
+- }
+-}
+ /*
+ * Checks to see if the hardware supports the state requested by var passed
+ * in. This function does not alter the hardware state! If the var passed in
+@@ -542,13 +319,15 @@
+ * PASSED in to what we can do. If the hardware doesn't support mode change
+ * a -EINVAL will be returned by the upper layers.
+ */
+-static int fsl_diu_check_var(struct fb_var_screeninfo *var,
+- struct fb_info *info)
++static int fsl_diu_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
+ unsigned long htotal, vtotal;
++ struct mfb_info *pmfbi, *cmfbi, *mfbi = (struct mfb_info *)info->par;
++ int index = mfbi->index;
+
+- pr_debug("check_var xres: %d\n", var->xres);
+- pr_debug("check_var yres: %d\n", var->yres);
++ DPRINTK("Entered: fsl_diu_check_var\n");
++ DPRINTK("check_var xres: %d\n",var->xres);
++ DPRINTK("check_var yres: %d\n",var->yres);
+
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+@@ -568,8 +347,9 @@
+ var->yoffset = info->var.yres_virtual - info->var.yres;
+
+ if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
+- (var->bits_per_pixel != 16))
++ (var->bits_per_pixel != 16)) {
+ var->bits_per_pixel = default_bpp;
++ }
+
+ switch (var->bits_per_pixel) {
+ case 16:
+@@ -636,7 +416,7 @@
+ var->upper_margin;
+ var->pixclock = (vtotal * htotal * 6UL) / 100UL;
+ var->pixclock = KHZ2PICOS(var->pixclock);
+- pr_debug("pixclock set for 60Hz refresh = %u ps\n",
++ DPRINTK("pixclock set for 60Hz refresh = %u ps\n",
+ var->pixclock);
+ }
+
+@@ -648,154 +428,220 @@
+ var->sync |= var->nonstd;
+ var->nonstd |= var->sync;
+
+- adjust_aoi_size_position(var, info);
++ /* check AOI position */
++ switch (index) {
++ case 0:
++ if (mfbi->x_aoi_d != 0)
++ mfbi->x_aoi_d = 0;
++ if (mfbi->y_aoi_d != 0)
++ mfbi->y_aoi_d = 0;
++ break;
++ case 1: /* AOI 0 */
++ case 3:
++ cmfbi = (struct mfb_info *)fsl_diu_info[index+1].par;
++ if ((mfbi->x_aoi_d + var->xres) > fsl_diu_info[0].var.xres)
++ mfbi->x_aoi_d = fsl_diu_info[0].var.xres - var->xres;
++ if (mfbi->x_aoi_d < 0)
++ mfbi->x_aoi_d = 0;
++ if ((var->xres + mfbi->x_aoi_d) > fsl_diu_info[0].var.xres)
++ var->xres = fsl_diu_info[0].var.xres - mfbi->x_aoi_d;
++
++ if (cmfbi->count > 0) { /* AOI1 is open */
++ if ((mfbi->y_aoi_d + var->yres) > cmfbi->y_aoi_d)
++ mfbi->y_aoi_d = cmfbi->y_aoi_d - var->yres;
++ if (mfbi->y_aoi_d < 0)
++ mfbi->y_aoi_d = 0;
++ if ((var->yres + mfbi->y_aoi_d) > cmfbi->y_aoi_d)
++ var->yres = cmfbi->y_aoi_d - mfbi->y_aoi_d;
++ }
++ else { /* AOI1 is close */
++ if ((mfbi->y_aoi_d + var->yres) > fsl_diu_info[0].var.yres)
++ mfbi->y_aoi_d = fsl_diu_info[0].var.yres - var->yres;
++ if (mfbi->y_aoi_d < 0)
++ mfbi->y_aoi_d = 0;
++ if ((var->yres + mfbi->y_aoi_d) > fsl_diu_info[0].var.yres)
++ var->yres = fsl_diu_info[0].var.yres - mfbi->y_aoi_d;
++ }
++ break;
++ case 2: /* AOI 1 */
++ case 4:
++ pmfbi = (struct mfb_info *)fsl_diu_info[index-1].par;
++ if ((mfbi->x_aoi_d + var->xres) > fsl_diu_info[0].var.xres)
++ mfbi->x_aoi_d = fsl_diu_info[0].var.xres - var->xres;
++ if (mfbi->x_aoi_d < 0)
++ mfbi->x_aoi_d = 0;
++ if ((var->xres + mfbi->x_aoi_d) > fsl_diu_info[0].var.xres)
++ var->xres = fsl_diu_info[0].var.xres - mfbi->x_aoi_d;
++
++ if (pmfbi->count > 0) { /* AOI0 is open */
++ if ((mfbi->y_aoi_d + var->yres) > fsl_diu_info[0].var.yres)
++ mfbi->y_aoi_d = fsl_diu_info[0].var.yres - var->yres;
++ if (mfbi->y_aoi_d < (pmfbi->y_aoi_d+fsl_diu_info[index-1].var.yres))
++ mfbi->y_aoi_d = pmfbi->y_aoi_d+fsl_diu_info[index-1].var.yres;
++ if ((var->yres + mfbi->y_aoi_d) > fsl_diu_info[0].var.yres)
++ var->yres = fsl_diu_info[0].var.yres - mfbi->y_aoi_d;
++ }
++ else { /* AOI0 is close */
++ if ((mfbi->y_aoi_d + var->yres) > fsl_diu_info[0].var.yres)
++ mfbi->y_aoi_d = fsl_diu_info[0].var.yres - var->yres;
++ if (mfbi->y_aoi_d < 0)
++ mfbi->y_aoi_d = 0;
++ if ((var->yres + mfbi->y_aoi_d) > fsl_diu_info[0].var.yres)
++ var->yres = fsl_diu_info[0].var.yres - mfbi->y_aoi_d;
++ }
++ break;
++ }
+ return 0;
+ }
+
+-static void set_fix(struct fb_info *info)
++static void hide_cursor(struct fb_info *info)
+ {
+- struct fb_fix_screeninfo *fix = &info->fix;
+- struct fb_var_screeninfo *var = &info->var;
+- struct mfb_info *mfbi = info->par;
++ struct diu *pdiu = dr.diu_reg;
++ write_reg_wa(&(pdiu->curs_pos), OUT_DISP_AREA);
++}
+
+- strncpy(fix->id, mfbi->id, strlen(mfbi->id));
+- fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+- fix->type = FB_TYPE_PACKED_PIXELS;
+- fix->accel = FB_ACCEL_NONE;
+- fix->visual = FB_VISUAL_TRUECOLOR;
+- fix->xpanstep = 1;
+- fix->ypanstep = 1;
++static void show_cursor(struct fb_info *info)
++{
++ struct diu *pdiu = dr.diu_reg;
++ write_reg_wa(&pdiu->cursor, pool.cursor.paddr);
+ }
+
+-static void update_lcdc(struct fb_info *info)
++/*
++ * Copies a cursor image from user space to the proper place in driver
++ * memory so that the hardware can display the cursor image
++ */
++static void load_cursor_image(struct fb_info *info, u8 *data,
++ u16 bg, u16 fg, u32 w, u32 h, u32 d)
+ {
+- struct fb_var_screeninfo *var = &info->var;
+- struct mfb_info *mfbi = info->par;
+- struct fsl_diu_data *machine_data = mfbi->parent;
+- struct diu *hw;
++ u16 *dst = (u16 *)(pool.cursor.vaddr + pool.cursor.offset);
+ int i, j;
+- char __iomem *cursor_base, *gamma_table_base;
+-
+- u32 temp;
++ u8 *s;
+
+- hw = dr.diu_reg;
++ s = data;
++ for (i = h; i--; ) {
++ for (j = 0; j < w; j++) {
++ if (*s & (1 << j))
++ *(dst + j) = cpu_to_le16(fg);
++ else
++ *(dst + j) = cpu_to_le16(bg);
++ }
+
+- if (mfbi->type == MFB_TYPE_OFF) {
+- fsl_diu_disable_panel(info);
+- return;
++ dst += 32;
++ s++;
+ }
++}
+
+- diu_ops.set_monitor_port(machine_data->monitor_port);
+- gamma_table_base = pool.gamma.vaddr;
+- cursor_base = pool.cursor.vaddr;
+- /* Prep for DIU init - gamma table, cursor table */
++/*
++ * A cursor function that supports displaying a cursor image via hardware.
++ * Within the kernel, copy and invert rops are supported. If exported
++ * to user space, only the copy rop will be supported.
++ */
++static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor)
++{
++ struct mfb_info *mfbi = (struct mfb_info *)info->par;
++ struct diu *pdiu = dr.diu_reg;
++ int set = cursor->set;
++ u16 fg, bg;
++ static u32 curs_pos;
+
+- for (i = 0; i <= 2; i++)
+- for (j = 0; j <= 255; j++)
+- *gamma_table_base++ = j;
++ if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
++ return -EINVAL;
+
+- diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr);
++ if (!hwcursor)
++ return -ENODEV;
+
+- pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw);
+- disable_lcdc(info);
++ if (mfbi->cursor_reset) {
++ set = FB_CUR_SETALL;
++ mfbi->cursor_reset = 0;
++ }
++
++ if (set & FB_CUR_SETSIZE)
++ memset_io(pool.cursor.vaddr + pool.cursor.offset,
++ 0, MAX_CURS * MAX_CURS * 4);
++
++ if (set & FB_CUR_SETPOS) {
++ u32 xx, yy, temp;
++ yy = cursor->image.dy - info->var.yoffset;
++ xx = cursor->image.dx - info->var.xoffset;
++ temp = xx & 0xFFFF;
++ temp |= yy << 16;
++ write_reg(&(pdiu->curs_pos), temp);
++ }
++
++ if (set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
++ u32 i, dsize, s_pitch, s_pitch_max;
++ u32 bg_idx = cursor->image.bg_color;
++ u32 fg_idx = cursor->image.fg_color;
++ u8 *src;
++
++ if (info->state != FBINFO_STATE_RUNNING)
++ return 0;
++
++ s_pitch = (cursor->image.width + 7) >> 3;
++ s_pitch_max = (MAX_CURS + 7) >> 3;
++ dsize = s_pitch * cursor->image.height;
++
++ bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
++ ((info->cmap.green[bg_idx] & 0xf8) << 2) |
++ ((info->cmap.blue[bg_idx] & 0xf8) >> 3) |
++ 1 << 15;
++
++ fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
++ ((info->cmap.green[fg_idx] & 0xf8) << 2) |
++ ((info->cmap.blue[fg_idx] & 0xf8) >> 3) |
++ 1 << 15;
++
++ src = kmalloc(s_pitch_max * cursor->image.height,
++ GFP_ATOMIC);
++ if (cursor->enable) {
++ switch (cursor->rop) {
++ case ROP_XOR:
++ for (i = 0; i < dsize; i++)
++ src[i] = cursor->image.data[i] ^
++ cursor->mask[i];
++ break;
++ case ROP_COPY:
++ default:
++ for (i = 0; i < dsize; i++)
++ src[i] = cursor->image.data[i] &
++ cursor->mask[i];
++ break;
++ }
++ } else
++ memcpy(src, cursor->image.data, dsize);
+
+- /* Program DIU registers */
++ load_cursor_image(info, src, bg, fg,
++ cursor->image.width,
++ cursor->image.height,
++ cursor->image.depth);
++ show_cursor(info);
++ kfree(src);
++ } else if (cursor->enable && cursor->rop == ROP_XOR) {
++ if (pdiu->curs_pos != OUT_DISP_AREA) {
++ curs_pos = pdiu->curs_pos;
++ write_reg(&(pdiu->curs_pos), OUT_DISP_AREA);
++ } else
++ write_reg(&(pdiu->curs_pos), curs_pos);
++ }
+
+- out_be32(&hw->gamma, pool.gamma.paddr);
+- out_be32(&hw->cursor, pool.cursor.paddr);
++ return 0;
++}
+
+- out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */
+- out_be32(&hw->bgnd_wb, 0); /* BGND_WB */
+- out_be32(&hw->disp_size, (var->yres << 16 | var->xres));
+- /* DISP SIZE */
+- pr_debug("DIU xres: %d\n", var->xres);
+- pr_debug("DIU yres: %d\n", var->yres);
++/*
++ * Using the fb_var_screeninfo in fb_info we set the aoi of this
++ * particular framebuffer. It is a light version of fsl_diu_set_par.
++ */
++static int fsl_diu_set_aoi(struct fb_info *info)
++{
++ struct fb_var_screeninfo *var = &info->var;
++ struct mfb_info *mfbi = info->par;
++ struct diu_ad *ad = mfbi->ad;
+
+- out_be32(&hw->wb_size, 0); /* WB SIZE */
+- out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */
+-
+- /* Horizontal and vertical configuration register */
+- temp = var->left_margin << 22 | /* BP_H */
+- var->hsync_len << 11 | /* PW_H */
+- var->right_margin; /* FP_H */
+-
+- out_be32(&hw->hsyn_para, temp);
+-
+- temp = var->upper_margin << 22 | /* BP_V */
+- var->vsync_len << 11 | /* PW_V */
+- var->lower_margin; /* FP_V */
+-
+- out_be32(&hw->vsyn_para, temp);
+-
+- pr_debug("DIU right_margin - %d\n", var->right_margin);
+- pr_debug("DIU left_margin - %d\n", var->left_margin);
+- pr_debug("DIU hsync_len - %d\n", var->hsync_len);
+- pr_debug("DIU upper_margin - %d\n", var->upper_margin);
+- pr_debug("DIU lower_margin - %d\n", var->lower_margin);
+- pr_debug("DIU vsync_len - %d\n", var->vsync_len);
+- pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para);
+- pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para);
+-
+- diu_ops.set_pixel_clock(var->pixclock);
+-
+- out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */
+- out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */
+- out_be32(&hw->int_status, 0); /* INTERRUPT STATUS */
+- out_be32(&hw->plut, 0x01F5F666);
+-
+- /* Enable the DIU */
+- enable_lcdc(info);
+-}
+-
+-static int map_video_memory(struct fb_info *info)
+-{
+- phys_addr_t phys;
+-
+- pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual);
+- pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
+- pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
+-
+- info->fix.smem_len = info->fix.line_length * info->var.yres_virtual;
+- pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len);
+- info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys);
+- if (info->screen_base == NULL) {
+- printk(KERN_ERR "Unable to allocate fb memory\n");
+- return -ENOMEM;
+- }
+- info->fix.smem_start = (unsigned long) phys;
+- info->screen_size = info->fix.smem_len;
+-
+- pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n",
+- info->fix.smem_start,
+- info->fix.smem_len);
+- pr_debug("screen base %p\n", info->screen_base);
+-
+- return 0;
+-}
+-
+-static void unmap_video_memory(struct fb_info *info)
+-{
+- fsl_diu_free(info->screen_base, info->fix.smem_len);
+- info->screen_base = NULL;
+- info->fix.smem_start = 0;
+- info->fix.smem_len = 0;
+-}
+-
+-/*
+- * Using the fb_var_screeninfo in fb_info we set the aoi of this
+- * particular framebuffer. It is a light version of fsl_diu_set_par.
+- */
+-static int fsl_diu_set_aoi(struct fb_info *info)
+-{
+- struct fb_var_screeninfo *var = &info->var;
+- struct mfb_info *mfbi = info->par;
+- struct diu_ad *ad = mfbi->ad;
+-
+- /* AOI should not be greater than display size */
+- ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset);
+- ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
+- return 0;
+-}
++ /* AOI should not be greater than display size */
++ ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset);
++ ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
++ return 0;
++}
+
+ /*
+ * Using the fb_var_screeninfo in fb_info we set the resolution of this
+@@ -809,60 +655,54 @@
+ {
+ unsigned long len;
+ struct fb_var_screeninfo *var = &info->var;
+- struct mfb_info *mfbi = info->par;
+- struct fsl_diu_data *machine_data = mfbi->parent;
++ struct mfb_info *mfbi = (struct mfb_info *)info->par;
+ struct diu_ad *ad = mfbi->ad;
+ struct diu *hw;
++ char byte_flip = 1;
+
++ DPRINTK("Entered: fsl_diu_set_par\n");
+ hw = dr.diu_reg;
+
+ set_fix(info);
++
++ /* Hide hardware cursor */
++ if (!hwcursor) {
++ hide_cursor(info);
++ info->fbops->fb_cursor = NULL;
++ } else
++ info->fbops->fb_cursor = fsl_diu_cursor;
++
+ mfbi->cursor_reset = 1;
+
+ len = info->var.yres_virtual * info->fix.line_length;
+ /* Alloc & dealloc each time resolution/bpp change */
+- if (len != info->fix.smem_len) {
++ if (len != info->fix.smem_len ) {
+ if (info->fix.smem_start)
+ unmap_video_memory(info);
+- pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len);
++ DPRINTK("SET PAR: smem_len = %d\n", info->fix.smem_len);
+
+ /* Memory allocation for framebuffer */
+ if (map_video_memory(info)) {
+- printk(KERN_ERR "Unable to allocate fb memory 1\n");
++ printk("Unable to allocate fb memory 1\n");
+ return -ENOMEM;
+ }
+ }
+
+- ad->pix_fmt =
+- diu_ops.get_pixel_format(var->bits_per_pixel,
+- machine_data->monitor_port);
++ ad->pix_fmt = platform_get_pixel_format(var->bits_per_pixel,
++ monitor_port, byte_flip);
+ ad->addr = cpu_to_le32(info->fix.smem_start);
+ ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) |
+ var->xres_virtual) | mfbi->g_alpha;
+ /* AOI should not be greater than display size */
+- ad->aoi_size = cpu_to_le32((var->yres << 16) | var->xres);
++ ad->aoi_size = cpu_to_le32(( var->yres << 16) | var->xres);
+ ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset);
+- ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
+-
+- /* Disable chroma keying function */
+- ad->ckmax_r = 0;
+- ad->ckmax_g = 0;
+- ad->ckmax_b = 0;
+-
+- ad->ckmin_r = 255;
+- ad->ckmin_g = 255;
+- ad->ckmin_b = 255;
++ ad->offset_xyd = cpu_to_le32(( mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
+
+ if (mfbi->index == 0)
+ update_lcdc(info);
+ return 0;
+ }
+
+-static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
+-{
+- return ((val<<width) + 0x7FFF - val)>>16;
+-}
+-
+ /*
+ * Set a single color register. The values supplied have a 16 bit magnitude
+ * which needs to be scaled in this function for the hardware. Things to take
+@@ -875,45 +715,43 @@
+ static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info)
+ {
+- int ret = 1;
++ u32 *g_pal = (u32 *)pool.pallete.vaddr;
++ u32 *pal = info->pseudo_palette;
++ struct diu *hw;
++ u32 v;
+
+- /*
+- * If greyscale is true, then we convert the RGB value
+- * to greyscale no matter what visual we are using.
+- */
+- if (info->var.grayscale)
+- red = green = blue = (19595 * red + 38470 * green +
+- 7471 * blue) >> 16;
+- switch (info->fix.visual) {
+- case FB_VISUAL_TRUECOLOR:
+- /*
+- * 16-bit True Colour. We encode the RGB value
+- * according to the RGB bitfield information.
+- */
+- if (regno < 16) {
+- u32 *pal = info->pseudo_palette;
+- u32 v;
+-
+- red = CNVT_TOHW(red, info->var.red.length);
+- green = CNVT_TOHW(green, info->var.green.length);
+- blue = CNVT_TOHW(blue, info->var.blue.length);
+- transp = CNVT_TOHW(transp, info->var.transp.length);
+-
+- v = (red << info->var.red.offset) |
+- (green << info->var.green.offset) |
+- (blue << info->var.blue.offset) |
+- (transp << info->var.transp.offset);
++ if (regno > (MFB_PALETTE_ENTRIES - 1))
++ return -EINVAL;
+
+- pal[regno] = v;
+- ret = 0;
++ if (info->var.bits_per_pixel > 8) {
++#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
++ red = CNVT_TOHW(red, info->var.red.length);
++ green = CNVT_TOHW(green, info->var.green.length);
++ blue = CNVT_TOHW(blue, info->var.blue.length);
++ transp = CNVT_TOHW(transp, info->var.transp.length);
++#undef CNVT_TOHW
++ v = (red << info->var.red.offset) |
++ (green << info->var.green.offset) |
++ (blue << info->var.blue.offset) |
++ (transp << info->var.transp.offset);
++ pal[regno] = v;
++
++ } else { /* bits_per_pixel == 8 */
++ g_pal += 2 * regno;
++ red >>= 8;
++ green >>= 8;
++ blue >>= 8;
++ transp >>= 8;
++ *g_pal = cpu_to_le32(transp << 24 | red << 16 |
++ green << 8 | blue);
++
++ if (regno >= (MFB_PALETTE_ENTRIES - 1)) {
++ hw = dr.diu_reg;
++ write_reg_wa(&(hw->pallete), pool.pallete.paddr);
+ }
+- break;
+- case FB_VISUAL_STATIC_PSEUDOCOLOR:
+- case FB_VISUAL_PSEUDOCOLOR:
+- break;
+ }
+
+- return ret;
++ return (0);
+ }
+
+ /*
+@@ -924,9 +762,11 @@
+ static int fsl_diu_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+ {
++ DPRINTK("Entered: fsl_diu_pan_display\n");
+ if ((info->var.xoffset == var->xoffset) &&
+- (info->var.yoffset == var->yoffset))
++ (info->var.yoffset == var->yoffset)) {
+ return 0; /* No change, do nothing */
++ }
+
+ if (var->xoffset < 0 || var->yoffset < 0
+ || var->xoffset + info->var.xres > info->var.xres_virtual
+@@ -936,16 +776,136 @@
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
+
+- if (var->vmode & FB_VMODE_YWRAP)
++ if (var->vmode & FB_VMODE_YWRAP) {
+ info->var.vmode |= FB_VMODE_YWRAP;
+- else
++ } else {
+ info->var.vmode &= ~FB_VMODE_YWRAP;
++ }
+
+ fsl_diu_set_aoi(info);
+
+ return 0;
+ }
+
++static int fsl_diu_enable_panel(struct fb_info *info)
++{
++ struct mfb_info *pmfbi, *cmfbi, *mfbi = (struct mfb_info *)info->par;
++ struct diu *hw = dr.diu_reg;
++ struct diu_ad *ad = mfbi->ad;
++ int res = 0;
++
++ DPRINTK("Entered: enable_panel index %d\n",mfbi->index);
++ if(mfbi->type != MFB_TYPE_OFF) {
++ switch (mfbi->index) {
++ case 0: /* plane 0 */
++ if (hw->desc[0] != ad->paddr)
++ write_reg_wa(&(hw->desc[0]), ad->paddr);
++ break;
++ case 1: /* plane 1 AOI 0 */
++ cmfbi = (struct mfb_info *) fsl_diu_info[2].par;
++ if (hw->desc[1] != ad->paddr) { /* AOI0 was closed */
++ if (cmfbi->count > 0) /* AOI1 is open */
++ ad->next_ad = cpu_to_le32(cmfbi->ad->paddr);
++ else
++ ad->next_ad = 0;
++ write_reg_wa(&(hw->desc[1]), ad->paddr);
++ }
++ break;
++ case 3: /* plane 2 AOI 0 */
++ cmfbi = (struct mfb_info *) fsl_diu_info[4].par;
++ if (hw->desc[2] != ad->paddr) { /* AOI0 was closed */
++ if (cmfbi->count > 0) /* AOI1 is open */
++ ad->next_ad = cpu_to_le32(cmfbi->ad->paddr);
++ else
++ ad->next_ad = 0;
++ write_reg_wa(&(hw->desc[2]), ad->paddr);
++ }
++ break;
++ case 2: /* plane 1 AOI 1 */
++ pmfbi = (struct mfb_info *)fsl_diu_info[1].par;
++ ad->next_ad = 0;
++ if (hw->desc[1] == dummy_ad->paddr) /* AOI0 was closed */
++ write_reg_wa(&(hw->desc[1]), ad->paddr);
++ else /* AOI0 was open */
++ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
++ break;
++ case 4: /* plane 2 AOI 1 */
++ pmfbi = (struct mfb_info *)fsl_diu_info[3].par;
++ ad->next_ad = 0;
++ if (hw->desc[2] == dummy_ad->paddr) /* AOI0 was closed */
++ write_reg_wa(&(hw->desc[2]), ad->paddr);
++ else /* AOI0 was open */
++ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
++ break;
++ default:
++ res = -EINVAL;
++ break;
++ }
++ }
++ else
++ res = -EINVAL;
++ return res;
++}
++
++static int fsl_diu_disable_panel(struct fb_info *info)
++{
++ struct mfb_info *pmfbi, *cmfbi, *mfbi = (struct mfb_info *)info->par;
++ struct diu *hw = dr.diu_reg;
++ struct diu_ad *ad = mfbi->ad;
++ int res = 0;
++
++ DPRINTK("Entered: disable_panel\n");
++ switch (mfbi->index) {
++ case 0: /* plane 0 */
++ if (hw->desc[0] != dummy_ad->paddr)
++ write_reg_wa(&(hw->desc[0]), dummy_ad->paddr);
++ break;
++ case 1: /* plane 1 AOI 0 */
++ cmfbi = (struct mfb_info *) fsl_diu_info[2].par;
++ if (cmfbi->count > 0) /* AOI1 is open */
++ write_reg_wa(&(hw->desc[1]), cmfbi->ad->paddr);
++ /* move AOI1 to the first */
++ else /* AOI1 was closed */
++ write_reg_wa(&(hw->desc[1]), dummy_ad->paddr);
++ /* close AOI 0 */
++ break;
++ case 3: /* plane 2 AOI 0 */
++ cmfbi = (struct mfb_info *) fsl_diu_info[4].par;
++ if (cmfbi->count > 0) /* AOI1 is open */
++ write_reg_wa(&(hw->desc[2]), cmfbi->ad->paddr);
++ /* move AOI1 to the first */
++ else /* AOI1 was closed */
++ write_reg_wa(&(hw->desc[2]), dummy_ad->paddr);
++ /* close AOI 0 */
++ break;
++ case 2: /* plane 1 AOI 1 */
++ pmfbi = (struct mfb_info *)fsl_diu_info[1].par;
++ if (hw->desc[1] != ad->paddr) { /* AOI1 is not the first in the chain */
++ if (pmfbi->count > 0) /* AOI0 is open, must be the first */
++ pmfbi->ad->next_ad = 0;
++ }
++ else /* AOI1 is the first in the chain */
++ write_reg_wa(&(hw->desc[1]), dummy_ad->paddr);
++ /* close AOI 1 */
++ break;
++ case 4: /* plane 2 AOI 1 */
++ pmfbi = (struct mfb_info *)fsl_diu_info[3].par;
++ if (hw->desc[2] != ad->paddr) { /* AOI1 is not the first in the chain */
++ if (pmfbi->count > 0) /* AOI0 is open, must be the first */
++ pmfbi->ad->next_ad = 0;
++ }
++ else /* AOI1 is the first in the chain */
++ write_reg_wa(&(hw->desc[2]), dummy_ad->paddr);
++ /* close AOI 1 */
++ break;
++ default:
++ res = -EINVAL;
++ break;
++ }
++
++ return res;
++}
++
+ /*
+ * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking
+ * succeeded, != 0 if un-/blanking failed.
+@@ -955,8 +915,9 @@
+ */
+ static int fsl_diu_blank(int blank_mode, struct fb_info *info)
+ {
+- struct mfb_info *mfbi = info->par;
++ struct mfb_info *mfbi = (struct mfb_info *)info->par;
+
++ DPRINTK("Entered: fsl_diu_blank\n");
+ mfbi->blank = blank_mode;
+
+ switch (blank_mode) {
+@@ -980,179 +941,191 @@
+ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+ {
+- struct mfb_info *mfbi = info->par;
++ struct mfb_info *mfbi = (struct mfb_info *)info->par;
++ struct fb_var_screeninfo *var = &info->var;
+ struct diu_ad *ad = mfbi->ad;
+ struct mfb_chroma_key ck;
+ unsigned char global_alpha;
+ struct aoi_display_offset aoi_d;
+- __u32 pix_fmt;
+- void __user *buf = (void __user *)arg;
++ struct diu *hw = dr.diu_reg;
++ u32 ck_tmp;
++ char byte_flip;
++ int ret;
+
+- if (!arg)
+- return -EINVAL;
++ DPRINTK("Entered: fsl_diu_ioctl\n");
+ switch (cmd) {
+- case MFB_SET_PIXFMT:
+- if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt)))
+- return -EFAULT;
+- ad->pix_fmt = pix_fmt;
+- pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt);
+- break;
+- case MFB_GET_PIXFMT:
+- pix_fmt = ad->pix_fmt;
+- if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt)))
+- return -EFAULT;
+- pr_debug("get pixel format 0x%08x\n", ad->pix_fmt);
+- break;
+ case MFB_SET_AOID:
+- if (copy_from_user(&aoi_d, buf, sizeof(aoi_d)))
++ if (!arg)
++ return -EINVAL;
++ if (copy_from_user((void *)&aoi_d, (void *)arg, sizeof(aoi_d)))
+ return -EFAULT;
+ mfbi->x_aoi_d = aoi_d.x_aoi_d;
+ mfbi->y_aoi_d = aoi_d.y_aoi_d;
+- pr_debug("set AOI display offset of index %d to (%d,%d)\n",
+- mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
+- fsl_diu_check_var(&info->var, info);
++ DPRINTK("set AOI display offset of index %d to (%d,%d)\n",mfbi->index,aoi_d.x_aoi_d,aoi_d.y_aoi_d);
++ fsl_diu_check_var(&info->var,info);
+ fsl_diu_set_aoi(info);
+ break;
+ case MFB_GET_AOID:
++ if (!arg)
++ return -EINVAL;
+ aoi_d.x_aoi_d = mfbi->x_aoi_d;
+ aoi_d.y_aoi_d = mfbi->y_aoi_d;
+- if (copy_to_user(buf, &aoi_d, sizeof(aoi_d)))
++ if (copy_to_user((void *)arg, (void *)&aoi_d, sizeof(aoi_d)))
+ return -EFAULT;
+- pr_debug("get AOI display offset of index %d (%d,%d)\n",
+- mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
++ DPRINTK("get AOI display offset of index %d (%d,%d)\n",mfbi->index,aoi_d.x_aoi_d,aoi_d.y_aoi_d);
+ break;
+ case MFB_GET_ALPHA:
++ if (!arg)
++ return -EINVAL;
+ global_alpha = mfbi->g_alpha;
+- if (copy_to_user(buf, &global_alpha, sizeof(global_alpha)))
++ if (copy_to_user((void *)arg, (void *)&global_alpha, sizeof(global_alpha)))
+ return -EFAULT;
+- pr_debug("get global alpha of index %d\n", mfbi->index);
++ DPRINTK("get global alpha of index %d\n",mfbi->index);
+ break;
+ case MFB_SET_ALPHA:
++ if (!arg)
++ return -EINVAL;
++
+ /* set panel information */
+- if (copy_from_user(&global_alpha, buf, sizeof(global_alpha)))
++ if (copy_from_user((void *)&global_alpha, (void *)arg, sizeof(global_alpha)))
+ return -EFAULT;
+- ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) |
+- (global_alpha & 0xff);
++ ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) | (global_alpha & 0xff);
+ mfbi->g_alpha = global_alpha;
+- pr_debug("set global alpha for index %d\n", mfbi->index);
++ DPRINTK("set global alpha for index %d\n",mfbi->index);
+ break;
+ case MFB_SET_CHROMA_KEY:
+- /* set panel winformation */
+- if (copy_from_user(&ck, buf, sizeof(ck)))
++ if (!arg)
++ return -EINVAL;
++
++ /* set color-keying information */
++ if (copy_from_user((void *)&ck, (void *)arg, sizeof(ck)))
+ return -EFAULT;
+
+- if (ck.enable &&
++ if(ck.enable &&
+ (ck.red_max < ck.red_min ||
+ ck.green_max < ck.green_min ||
+ ck.blue_max < ck.blue_min))
+ return -EINVAL;
+
+- if (!ck.enable) {
+- ad->ckmax_r = 0;
+- ad->ckmax_g = 0;
+- ad->ckmax_b = 0;
+- ad->ckmin_r = 255;
+- ad->ckmin_g = 255;
+- ad->ckmin_b = 255;
++ if(!ck.enable) {
++ ad->ckmax_bgr = 0;
++ ad->ckmin_bgr = cpu_to_le32(0x00ffffff);
+ } else {
+- ad->ckmax_r = ck.red_max;
+- ad->ckmax_g = ck.green_max;
+- ad->ckmax_b = ck.blue_max;
+- ad->ckmin_r = ck.red_min;
+- ad->ckmin_g = ck.green_min;
+- ad->ckmin_b = ck.blue_min;
++ ad->ckmax_bgr = cpu_to_le32(ck.blue_max << 16 |
++ ck.green_max << 8 |
++ ck.red_max);
++ ad->ckmin_bgr = cpu_to_le32(ck.blue_min << 16 |
++ ck.green_min << 8 |
++ ck.red_min);
+ }
+- pr_debug("set chroma key\n");
++ DPRINTK("set chroma key\n");
++ break;
++ case MFB_GET_CHROMA_KEY:
++ if (!arg)
++ return -EINVAL;
++
++ ck_tmp = cpu_to_le32(ad->ckmax_bgr);
++ ck.red_max = ck_tmp & 0xff;
++ ck.green_max = (ck_tmp >> 8) & 0xff;
++ ck.blue_max = (ck_tmp >> 16) & 0xff;
++
++ ck_tmp = cpu_to_le32(ad->ckmin_bgr);
++ ck.red_min = ck_tmp & 0xff;
++ ck.green_min = (ck_tmp >> 8) & 0xff;
++ ck.blue_min = (ck_tmp >> 16) & 0xff;
++
++ /* get color-keying information */
++ if (copy_to_user((void *)arg, (void *)&ck, sizeof(ck)))
++ return -EFAULT;
++
++ break;
++ case MFB_SET_BYTE_FLIP:
++ if (arg)
++ byte_flip = 1;
++ else
++ byte_flip = 0;
++ ad->pix_fmt = platform_get_pixel_format(var->bits_per_pixel,
++ monitor_port, byte_flip);
+ break;
+ case FBIOGET_GWINFO:
+ if (mfbi->type == MFB_TYPE_OFF)
+ return -ENODEV;
++
++ if (!arg)
++ return -EINVAL;
++
+ /* get graphic window information */
+- if (copy_to_user(buf, ad, sizeof(*ad)))
++ if (copy_to_user((void *)arg, (void *)ad, sizeof(*ad)))
+ return -EFAULT;
+ break;
+ case FBIOGET_HWCINFO:
+- pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO);
++ printk("%s, FBIOGET_HWCINFO:0x%08x\n", __func__, FBIOGET_HWCINFO);
+ break;
+ case FBIOPUT_MODEINFO:
+- pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO);
++ printk("%s, FBIOPUT_MODEINFO:0x%08x\n", __func__, FBIOPUT_MODEINFO);
+ break;
+ case FBIOGET_DISPINFO:
+- pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO);
++ printk("%s, FBIOGET_DISPINFO:0x%08x\n", __func__, FBIOGET_DISPINFO);
++ break;
++ case MFB_WAIT_FOR_VSYNC:
++ if (!arg)
++ return -EINVAL;
++ mfbi = (struct mfb_info *)fsl_diu_info[0].par;
++ ret = wait_for_vsync();
++ if (copy_to_user((void *)arg, (void *)&ret, sizeof(ret)))
++ return -EFAULT;
++ break;
++ case MFB_SET_GAMMA:
++ if (!arg)
++ return -EINVAL;
++ /* set the gamma table */
++ DPRINTK("MFB_SET_GAMMA s\n");
++ if (copy_from_user
++ ((void *)pool.gamma.vaddr, (void *)arg, 3*256))
++ return -EFAULT;
++ write_reg_wa(&(hw->gamma), pool.gamma.paddr);
++ break;
++ case MFB_GET_GAMMA:
++ if (!arg)
++ return -EINVAL;
++ /* get the gamma table */
++ DPRINTK("MFB_GET_GAMMA \n");
++ if (copy_to_user
++ ((void *)arg, (void *)pool.gamma.vaddr, 3*256))
++ return -EFAULT;
++ write_reg_wa(&(hw->gamma), pool.gamma.paddr);
+ break;
+
+ default:
+- printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd);
+- return -ENOIOCTLCMD;
++ printk("Unknown ioctl command (0x%08X)\n", cmd);
++ return 0;
+ }
+
+ return 0;
+ }
+
+-/* turn on fb if count == 1
+- */
+-static int fsl_diu_open(struct fb_info *info, int user)
+-{
+- struct mfb_info *mfbi = info->par;
+- int res = 0;
+-
+- spin_lock(&diu_lock);
+- mfbi->count++;
+- if (mfbi->count == 1) {
+- pr_debug("open plane index %d\n", mfbi->index);
+- fsl_diu_check_var(&info->var, info);
+- res = fsl_diu_set_par(info);
+- if (res < 0)
+- mfbi->count--;
+- else {
+- res = fsl_diu_enable_panel(info);
+- if (res < 0)
+- mfbi->count--;
+- }
+- }
+-
+- spin_unlock(&diu_lock);
+- return res;
+-}
+-
+-/* turn off fb if count == 0
+- */
+-static int fsl_diu_release(struct fb_info *info, int user)
++static void set_fix(struct fb_info *info)
+ {
+- struct mfb_info *mfbi = info->par;
+- int res = 0;
++ struct fb_fix_screeninfo *fix = &info->fix;
++ struct fb_var_screeninfo *var = &info->var;
++ struct mfb_info *mfbi = (struct mfb_info *)info->par;
+
+- spin_lock(&diu_lock);
+- mfbi->count--;
+- if (mfbi->count == 0) {
+- pr_debug("release plane index %d\n", mfbi->index);
+- res = fsl_diu_disable_panel(info);
+- if (res < 0)
+- mfbi->count++;
+- }
+- spin_unlock(&diu_lock);
+- return res;
++ DPRINTK("Entered: set_fix\n");
++ strncpy(fix->id, mfbi->id, strlen(mfbi->id));
++ fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
++ fix->type = FB_TYPE_PACKED_PIXELS;
++ fix->accel = FB_ACCEL_NONE;
++ fix->visual = FB_VISUAL_TRUECOLOR;
++ fix->xpanstep = 1;
++ fix->ypanstep = 1;
+ }
+
+-static struct fb_ops fsl_diu_ops = {
+- .owner = THIS_MODULE,
+- .fb_check_var = fsl_diu_check_var,
+- .fb_set_par = fsl_diu_set_par,
+- .fb_setcolreg = fsl_diu_setcolreg,
+- .fb_blank = fsl_diu_blank,
+- .fb_pan_display = fsl_diu_pan_display,
+- .fb_fillrect = cfb_fillrect,
+- .fb_copyarea = cfb_copyarea,
+- .fb_imageblit = cfb_imageblit,
+- .fb_ioctl = fsl_diu_ioctl,
+- .fb_open = fsl_diu_open,
+- .fb_release = fsl_diu_release,
+-};
+-
+-static int init_fbinfo(struct fb_info *info)
++static int init_fbinfo(struct fb_info *info,
++ struct platform_device *pdev)
+ {
+- struct mfb_info *mfbi = info->par;
++ struct mfb_info *mfbi = (struct mfb_info *)info->par;
+
++ DPRINTK("Entered: init_fbinfo\n");
+ info->device = NULL;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->fbops = &fsl_diu_ops;
+@@ -1160,89 +1133,92 @@
+ info->pseudo_palette = &mfbi->pseudo_palette;
+
+ /* Allocate colormap */
+- fb_alloc_cmap(&info->cmap, 16, 0);
++ fb_alloc_cmap(&info->cmap, 256, 0);
++ fb_set_cmap(&info->cmap, info);
++
+ return 0;
+ }
+
+-static int __devinit install_fb(struct fb_info *info)
++static int install_fb(struct fb_info *info,
++ struct platform_device *pdev)
+ {
+ int rc;
+- struct mfb_info *mfbi = info->par;
+- const char *aoi_mode, *init_aoi_mode = "320x240";
++ struct mfb_info *mfbi = (struct mfb_info *)info->par;
++ const char * aoi_mode, * init_aoi_mode ="320x240";
+
+- if (init_fbinfo(info))
++ DPRINTK("Entered: install_fb\n");
++ if (init_fbinfo(info, pdev))
+ return -EINVAL;
+
+ if (mfbi->index == 0) /* plane 0 */
+ aoi_mode = fb_mode;
+ else
+ aoi_mode = init_aoi_mode;
+- pr_debug("mode used = %s\n", aoi_mode);
+- rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
+- ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp);
++ DPRINTK("mode used = %s\n",aoi_mode);
++ rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db, ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp);
+
+ switch (rc) {
+ case 1:
+- pr_debug("using mode specified in @mode\n");
++ DPRINTK("using mode specified in @mode\n");
+ break;
+ case 2:
+- pr_debug("using mode specified in @mode "
+- "with ignored refresh rate\n");
++ DPRINTK("using mode specified in @mode with ignored refresh rate\n");
+ break;
+ case 3:
+- pr_debug("using mode default mode\n");
++ DPRINTK("using mode default mode\n");
+ break;
+ case 4:
+- pr_debug("using mode from list\n");
++ DPRINTK("using mode from list\n");
+ break;
+ default:
+- pr_debug("rc = %d\n", rc);
+- pr_debug("failed to find mode\n");
+- return -EINVAL;
++ DPRINTK("rc = %d\n", rc);
++ DPRINTK("failed to find mode\n");
++ return -EBUSY;
+ break;
+ }
+
+- pr_debug("xres_virtual %d\n", info->var.xres_virtual);
+- pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
++ DPRINTK("xres_virtual %d\n", info->var.xres_virtual);
++ DPRINTK("bits_per_pixel %d\n", info->var.bits_per_pixel);
+
+- pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
+- pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
++ DPRINTK("info->var.yres_virtual = %d\n", info->var.yres_virtual);
++ DPRINTK("info->fix.line_length = %d\n", info->fix.line_length);
+
+ if (mfbi->type == MFB_TYPE_OFF)
+ mfbi->blank = FB_BLANK_NORMAL;
+ else
+ mfbi->blank = FB_BLANK_UNBLANK;
+
+- if (fsl_diu_check_var(&info->var, info)) {
+- printk(KERN_ERR "fb_check_var failed");
++ if (fsl_diu_check_var(&info->var,info)) {
++ printk("fb_check_var failed");
+ fb_dealloc_cmap(&info->cmap);
+ return -EINVAL;
+ }
+
+ if (fsl_diu_set_par(info)) {
+- printk(KERN_ERR "fb_set_par failed");
++ printk("fb_set_par failed");
+ fb_dealloc_cmap(&info->cmap);
+ return -EINVAL;
+ }
+
+ if (register_framebuffer(info) < 0) {
+- printk(KERN_ERR "register_framebuffer failed");
++ printk("register_framebuffer failed");
+ unmap_video_memory(info);
+ fb_dealloc_cmap(&info->cmap);
+ return -EINVAL;
+ }
+
+ mfbi->registered = 1;
+- printk(KERN_INFO "fb%d: %s fb device registered successfully.\n",
++ printk("fb%d: %s fb device registered successfully.\n",
+ info->node, info->fix.id);
+
+ return 0;
+ }
+
+-static void uninstall_fb(struct fb_info *info)
++static void __exit uninstall_fb(struct fb_info *info)
+ {
+- struct mfb_info *mfbi = info->par;
++ struct mfb_info *mfbi = (struct mfb_info *)info->par;
+
++ DPRINTK("Entered: uninstall_fb\n");
+ if (!mfbi->registered)
+ return;
+
+@@ -1254,101 +1230,405 @@
+ mfbi->registered = 0;
+ }
+
+-static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
++static int map_video_memory(struct fb_info *info)
+ {
+- struct diu *hw = dr.diu_reg;
+- unsigned int status = in_be32(&hw->int_status);
++ DPRINTK("Entered: map_video_memory\n");
++ DPRINTK("info->var.xres_virtual = %d\n", info->var.xres_virtual);
++ DPRINTK("info->var.yres_virtual = %d\n", info->var.yres_virtual);
++ DPRINTK("info->fix.line_length = %d\n", info->fix.line_length);
+
+- if (status) {
+- /* This is the workaround for underrun */
+- if (status & INT_UNDRUN) {
+- out_be32(&hw->diu_mode, 0);
+- pr_debug("Err: DIU occurs underrun!\n");
+- udelay(1);
+- out_be32(&hw->diu_mode, 1);
+- }
+-#if defined(CONFIG_NOT_COHERENT_CACHE)
+- else if (status & INT_VSYNC) {
+- unsigned int i;
+- for (i = 0; i < coherence_data_size;
+- i += d_cache_line_size)
+- __asm__ __volatile__ (
+- "dcbz 0, %[input]"
+- ::[input]"r"(&coherence_data[i]));
+- }
+-#endif
+- return IRQ_HANDLED;
++ info->fix.smem_len = info->fix.line_length * info->var.yres_virtual;
++ DPRINTK("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len);
++ info->screen_base = fsl_diu_alloc(info->fix.smem_len,&info->fix.smem_start);
++ if (info->screen_base == 0) {
++ printk("Unable to allocate fb memory\n");
++ return -EBUSY;
+ }
+- return IRQ_NONE;
+-}
+
+-static int request_irq_local(int irq)
+-{
+- unsigned long status, ints;
+- struct diu *hw;
++ info->screen_size = info->fix.smem_len;
++
++ DPRINTK("Allocated fb @ paddr=0x%08lx, size=%d.\n", info->fix.smem_start,
++ info->fix.smem_len);
++ DPRINTK("screen base 0x%08lx\n",(long unsigned int) info->screen_base);
++
++ return 0;
++}
++
++static void unmap_video_memory(struct fb_info *info)
++{
++ DPRINTK("Entered: unmap_video_memory\n");
++ fsl_diu_free(info->screen_base,info->fix.smem_len);
++ info->screen_base = 0;
++ info->fix.smem_start = 0;
++ info->fix.smem_len = 0;
++}
++
++static void enable_lcdc(struct fb_info *info)
++{
++ struct diu *hw = dr.diu_reg;
++
++ DPRINTK("Entered: enable_lcdc\n");
++ if (!fb_enabled) {
++ write_reg(&(hw->diu_mode), dr.mode);
++ fb_enabled++;
++ }
++}
++
++static void disable_lcdc(struct fb_info *info)
++{
++ struct diu *hw = dr.diu_reg;
++
++ DPRINTK("Entered: disable_lcdc\n");
++ if (fb_enabled) {
++ write_reg(&(hw->diu_mode), 0);
++ fb_enabled = 0;
++ }
++}
++
++static void update_lcdc(struct fb_info *info)
++{
++ struct fb_var_screeninfo *var = &info->var;
++ struct mfb_info *mfbi = (struct mfb_info *)info->par;
++ struct diu *hw;
++ int i, j;
++ char __iomem *gamma_table_base;
++
++ u32 temp;
++
++ DPRINTK("Entered: update_lcdc\n");
++
++ spin_lock_init(&dr.reg_lock);
++ hw = dr.diu_reg;
++
++ if (mfbi->type == MFB_TYPE_OFF) {
++ fsl_diu_disable_panel(info);
++ return;
++ }
++
++ platform_set_monitor_port(monitor_port);
++
++ gamma_table_base = pool.gamma.vaddr;
++ /* Prep for DIU init - gamma table, cursor table */
++
++ for (i=0;i<=2;i++)
++ for(j=0;j<=255;j++)
++ *gamma_table_base++ = j;
++
++ platform_set_gamma_table(monitor_port, pool.gamma.vaddr);
++
++ DPRINTK("update-lcdc: HW - %p\n Disabling DIU\n", hw);
++ disable_lcdc(info);
++
++ /* Program DIU registers */
++ write_reg_wa(&(hw->gamma), pool.gamma.paddr);
++ write_reg_wa(&(hw->cursor), pool.cursor.paddr);
++ write_reg_wa(&(hw->pallete), pool.pallete.paddr);
++ memset(pool.cursor.vaddr + pool.cursor.offset, 0, 1024 * 4);
++ memset(pool.pallete.vaddr + pool.pallete.offset, 0, 256 * 4);
++
++ write_reg(&(hw->bgnd), 0x007F7F7F); /* BGND */
++ write_reg(&(hw->bgnd_wb), 0); /* BGND_WB */
++ write_reg(&(hw->disp_size), (var->yres << 16 | var->xres));
++ /* DISP SIZE */
++ DPRINTK("DIU xres: %d\n", var->xres);
++ DPRINTK("DIU yres: %d\n", var->yres);
++
++ write_reg(&(hw->wb_size), 0); /* WB SIZE */
++ write_reg(&(hw->wb_mem_addr), 0); /* WB MEM ADDR */
++
++ /* Horizontal and vertical configuration register */
++ temp = var->left_margin << 22 | /* BP_H */
++ var->hsync_len << 11 | /* PW_H */
++ var->right_margin; /* FP_H */
++
++ write_reg(&(hw->hsyn_para), temp);
++
++ temp = var->upper_margin << 22 | /* BP_V */
++ var->vsync_len << 11 | /* PW_V */
++ var->lower_margin; /* FP_V */
++
++ write_reg(&(hw->vsyn_para), temp);
++
++ DPRINTK("DIU right_margin - %d\n",var->right_margin);
++ DPRINTK("DIU left_margin - %d\n",var->left_margin);
++ DPRINTK("DIU hsync_len - %d\n",var->hsync_len);
++ DPRINTK("DIU upper_margin - %d\n",var->upper_margin);
++ DPRINTK("DIU lower_margin - %d\n",var->lower_margin);
++ DPRINTK("DIU vsync_len - %d\n",var->vsync_len);
++ DPRINTK("DIU HSYNC - 0x%08x\n",hw->hsyn_para);
++ DPRINTK("DIU VSYNC - 0x%08x\n",hw->vsyn_para);
++
++ platform_set_pixel_clock(var->pixclock);
++
++ write_reg(&(hw->syn_pol), 0); /* SYNC SIGNALS POLARITY */
++ write_reg(&(hw->thresholds), 0x00037800); /* The Thresholds */
++ write_reg(&(hw->int_status), 0); /* INTERRUPT STATUS */
++ write_reg(&(hw->int_mask), (0x1F&(~(INT_VSYNC | INT_UNDRUN)))); /* INT MASK */
++ write_reg(&(hw->plut),0x01F5F666);
++
++ /* Enable the DIU */
++ enable_lcdc(info);
++}
++
++static int wait_for_vsync(void)
++{
++ struct fsl_diu_vsync *vsync;
++ unsigned int count;
+ int ret;
+
++ vsync = &((struct mfb_info *)fsl_diu_info[0].par)->vsync;
++ count = vsync->count;
++ ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10);
++ if (ret < 0) {
++ return ret;
++ }
++ if (ret == 0) {
++ return -ETIMEDOUT;
++ }
++ return 0;
++}
++
++static void do_pending_buffer_flips(void)
++{
++ int i;
++ struct mfb_info *mfbi;
++ struct diu_ad *ad;
++
++ for (i = 0; i < ARRAY_SIZE(fsl_diu_info); i++) {
++ mfbi = (struct mfb_info *)fsl_diu_info[i].par;
++ ad = mfbi->ad;
++ if (ad && mfbi->vsync.addr) {
++ ad->addr = cpu_to_le32(mfbi->vsync.addr);
++ mfbi->vsync.addr = 0;
++ }
++ }
++}
++
++void fsl_diu_flip(unsigned long paddr)
++{
++ struct mfb_info *mfbi = (struct mfb_info *)fsl_diu_info[0].par;
++ struct diu_ad *ad = mfbi->ad;
++ if (ad) {
++#ifdef CONFIG_FSL_DIU_FLIP_ON_VSYNC
++ mfbi->vsync.addr = paddr;
++#else
++ ad->addr = cpu_to_le32(paddr);
++#endif
++ }
++}
++EXPORT_SYMBOL(fsl_diu_flip);
++
++void fsl_diu_flipn(int fbnum, unsigned long paddr, int now)
++{
++ struct mfb_info *mfbi = (struct mfb_info *)fsl_diu_info[fbnum].par;
++ struct diu_ad *ad = mfbi->ad;
++ if (ad) {
++ if (now)
++ ad->addr = cpu_to_le32(paddr);
++ else
++ mfbi->vsync.addr = paddr;
++ }
++}
++EXPORT_SYMBOL(fsl_diu_flipn);
++
++
++static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
++{
++ struct diu *hw = dr.diu_reg;
++ struct mfb_info *mfbi;
++ unsigned int status = read_reg(&(hw->int_status));
++
++ if (status) {
++ /* This is the workaround for underrun */
++ if (status & INT_UNDRUN) {
++ out_be32(&(hw->diu_mode), 0);
++ DPRINTK("Err: DIU occurs underrun!\n");
++ udelay(1);
++ out_be32(&(hw->diu_mode), 1);
++ }
++ else if (status & INT_VSYNC) {
++#if defined(CONFIG_NOT_COHERENT_CACHE)
++ int i;
++ unsigned int *ptr;
++ ptr = coherence_data;
++ for (i=0;i<1024*8;i++)
++ *ptr++ = 0;
++#endif
++ mfbi = (struct mfb_info *)fsl_diu_info[0].par;
++ mfbi->vsync.count++;
++ do_pending_buffer_flips();
++ wake_up_interruptible(&mfbi->vsync.wait);
++ }
++
++ return IRQ_HANDLED;
++ }
++ return IRQ_NONE;
++}
++
++/* FIXME: need to properly request IRQ will be used in future */
++static void request_irq_local(void)
++{
++ unsigned long status;
++ unsigned long flags;
++ struct diu *hw;
++ struct device_node *np;
++
++ DPRINTK("Entered: request_irq_local\n");
+ hw = dr.diu_reg;
+
+ /* Read to clear the status */
+- status = in_be32(&hw->int_status);
++ status = read_reg(&(hw->int_status));
++
++ np = of_find_node_by_type(NULL, "display");
++ if(!np) {
++ pr_info("Err: didn't find node 'lcd-controller' in device tree!\n");
++ return;
++ }
+
+- ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL);
+- if (ret)
+- pr_info("Request diu IRQ failed.\n");
++ irq = irq_of_parse_and_map(np, 0);
++ of_node_put(np);
++
++ if (request_irq(irq, fsl_diu_isr, 0, "LCDC", 0))
++ pr_info("Request LCDC IRQ failed.\n");
+ else {
+- ints = INT_PARERR | INT_LS_BF_VS;
++ spin_lock_irqsave(&fsl_diu_notifier_list.lock, flags);
++
++ /* Enable interrupt in case client has registered */
++ if (fsl_diu_notifier_list.head != NULL) {
++ unsigned long status;
++ unsigned long ints = INT_PARERR;
++
+ #if !defined(CONFIG_NOT_COHERENT_CACHE)
+- ints |= INT_VSYNC;
++ ints |= INT_VSYNC;
+ #endif
+- if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3)
++
++ if(dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3)
++ ints |= INT_VSYNC_WB;
++
++ /* Read to clear the status */
++ status = read_reg(&(hw->int_status));
++
++ /* Enable EOF, parameter error, and optional
++ * write back interrupt
++ */
++ write_reg(&(hw->int_mask), ints);
++ }
++
++ spin_unlock_irqrestore(&fsl_diu_notifier_list.lock, flags);
++ }
++}
++
++static void free_irq_local(void)
++{
++ struct diu *hw = dr.diu_reg;
++
++ DPRINTK("Entered: free_irq_local\n");
++ /* Disable all LCDC interrupt */
++ write_reg(&(hw->int_mask), 0x1f);
++
++ free_irq(irq, 0);
++}
++
++int fsl_diu_register_client(struct notifier_block *nb)
++{
++ unsigned long flags;
++ int ret;
++ struct diu *hw = dr.diu_reg;
++ DPRINTK("Entered: fsl_diu_register_client\n");
++
++ ret = atomic_notifier_chain_register(&fsl_diu_notifier_list, nb);
++
++ spin_lock_irqsave(&fsl_diu_notifier_list.lock, flags);
++
++ /* Enable interrupt in case client has registered */
++ if (fsl_diu_notifier_list.head != NULL) {
++ unsigned long status;
++ unsigned long ints = INT_PARERR;
++
++#if !defined(CONFIG_NOT_COHERENT_CACHE)
++ ints |= INT_VSYNC;
++#endif
++
++ if(dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3)
+ ints |= INT_VSYNC_WB;
+
+ /* Read to clear the status */
+- status = in_be32(&hw->int_status);
+- out_be32(&hw->int_mask, ints);
++ status = read_reg(&(hw->int_status));
++
++ /* Enable EOF, parameter error, and optional
++ * write back interrupt
++ */
++ write_reg(&(hw->int_mask), ints);
+ }
++
++ spin_unlock_irqrestore(&fsl_diu_notifier_list.lock, flags);
++
+ return ret;
+ }
+
+-static void free_irq_local(int irq)
++int fsl_diu_unregister_client(struct notifier_block *nb)
+ {
++ unsigned long flags;
++ int ret;
+ struct diu *hw = dr.diu_reg;
+
+- /* Disable all LCDC interrupt */
+- out_be32(&hw->int_mask, 0x1f);
++ DPRINTK("Entered: fsl_diu_unregister_client\n");
++ ret = atomic_notifier_chain_unregister(&fsl_diu_notifier_list, nb);
++
++ spin_lock_irqsave(&fsl_diu_notifier_list.lock, flags);
++
++ /* Mask interrupt in case no client registered */
++ if (fsl_diu_notifier_list.head == NULL)
++ write_reg(&(hw->int_mask), 0x1f);
++
++ spin_unlock_irqrestore(&fsl_diu_notifier_list.lock, flags);
+
+- free_irq(irq, NULL);
++ return ret;
+ }
+
+ #ifdef CONFIG_PM
++struct diu *reg;
++extern void mpc5121ads_diu_io_pm_restore(void);
++
+ /*
+ * Power management hooks. Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+-static int fsl_diu_suspend(struct of_device *ofdev, pm_message_t state)
++static int fsl_diu_suspend(struct platform_device *pdev, pm_message_t state)
+ {
+- struct fsl_diu_data *machine_data;
++ struct diu *hw = dr.diu_reg;
+
+- machine_data = dev_get_drvdata(&ofdev->dev);
+- disable_lcdc(machine_data->fsl_diu_info[0]);
++ reg = kmalloc(sizeof(struct diu), GFP_KERNEL);
++ if (!reg)
++ DPRINTK("No enough memory for storing DIU registers!\n");
++ else
++ memcpy(reg, hw, sizeof(struct diu));
++
++ DPRINTK("Entered: fsl_diu_suspend\n");
++ disable_lcdc(&fsl_diu_info[0]);
+
+ return 0;
+ }
+
+-static int fsl_diu_resume(struct of_device *ofdev)
++static int fsl_diu_resume(struct platform_device *pdev)
+ {
+- struct fsl_diu_data *machine_data;
++ struct diu *hw = dr.diu_reg;
++ u32 *i2c_intctrl_reg = ioremap(0x80001760, sizeof(u32));
++
++ DPRINTK("Entered: fsl_diu_resume\n");
++
++ /* Work around for I2C interrupt register lost after PM */
++ *i2c_intctrl_reg = 0x15000000;
+
+- machine_data = dev_get_drvdata(&ofdev->dev);
+- enable_lcdc(machine_data->fsl_diu_info[0]);
++ mpc5121ads_diu_io_pm_restore();
++ if (reg) {
++ memcpy(hw, reg, sizeof(struct diu));
++ kfree(reg);
++ }
+
+ return 0;
+ }
+
+-#else
+-#define fsl_diu_suspend NULL
+-#define fsl_diu_resume NULL
+ #endif /* CONFIG_PM */
+
+ /* Align to 64-bit(8-byte), 32-byte, etc. */
+@@ -1356,19 +1636,20 @@
+ {
+ u32 offset, ssize;
+ u32 mask;
+- dma_addr_t paddr = 0;
+
++ DPRINTK("Entered: allocate_buf\n");
+ ssize = size + bytes_align;
+- buf->vaddr = dma_alloc_coherent(NULL, ssize, &paddr, GFP_DMA |
+- __GFP_ZERO);
+- if (!buf->vaddr)
++ buf->vaddr = dma_alloc_coherent(0, ssize,
++ (dma_addr_t *) &(buf->paddr),
++ GFP_DMA | GFP_KERNEL);
++ if(!buf->vaddr)
+ return -ENOMEM;
+
+- buf->paddr = (__u32) paddr;
++ memset(buf->vaddr, 0, ssize);
+
+ mask = bytes_align - 1;
+ offset = (u32)buf->paddr & mask;
+- if (offset) {
++ if(offset) {
+ buf->offset = bytes_align - offset;
+ buf->paddr = (u32)buf->paddr + offset;
+ } else
+@@ -1378,234 +1659,196 @@
+
+ static void free_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
+ {
+- dma_free_coherent(NULL, size + bytes_align,
++ DPRINTK("Entered: free_buf\n");
++ dma_free_coherent(0, size + bytes_align,
+ buf->vaddr, (buf->paddr - buf->offset));
+ return;
+ }
+
+-static ssize_t store_monitor(struct device *device,
+- struct device_attribute *attr, const char *buf, size_t count)
++static ssize_t store_monitor(struct device *device, struct device_attribute *attr,
++ const char *buf, size_t count)
+ {
+- int old_monitor_port;
+- unsigned long val;
+- struct fsl_diu_data *machine_data =
+- container_of(attr, struct fsl_diu_data, dev_attr);
++ char ** last = NULL;
++ int val,old_monitor_port;
+
+- if (strict_strtoul(buf, 10, &val))
+- return 0;
++ val = simple_strtoul(buf, last, 0);
++
++ old_monitor_port = monitor_port;
+
+- old_monitor_port = machine_data->monitor_port;
+- machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val);
++ monitor_port = platform_set_sysfs_monitor_port(val);
+
+- if (old_monitor_port != machine_data->monitor_port) {
+- /* All AOIs need adjust pixel format
+- * fsl_diu_set_par only change the pixsel format here
+- * unlikely to fail. */
+- fsl_diu_set_par(machine_data->fsl_diu_info[0]);
+- fsl_diu_set_par(machine_data->fsl_diu_info[1]);
+- fsl_diu_set_par(machine_data->fsl_diu_info[2]);
+- fsl_diu_set_par(machine_data->fsl_diu_info[3]);
+- fsl_diu_set_par(machine_data->fsl_diu_info[4]);
++ if (old_monitor_port != monitor_port) { /* All AOIs need adjust pixel format */
++ fsl_diu_set_par (&fsl_diu_info[0]);
++ fsl_diu_set_par (&fsl_diu_info[1]);
++ fsl_diu_set_par (&fsl_diu_info[2]);
++ fsl_diu_set_par (&fsl_diu_info[3]);
++ fsl_diu_set_par (&fsl_diu_info[4]);
+ }
+ return count;
+ }
+
+-static ssize_t show_monitor(struct device *device,
+- struct device_attribute *attr, char *buf)
++static ssize_t show_monitor(struct device *device, struct device_attribute *attr,
++ char *buf)
+ {
+- struct fsl_diu_data *machine_data =
+- container_of(attr, struct fsl_diu_data, dev_attr);
+- return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
++ return platform_show_monitor_port(monitor_port, buf);
+ }
+
+-static int __devinit fsl_diu_probe(struct of_device *ofdev,
+- const struct of_device_id *match)
++static struct device_attribute device_attrs[] = {
++ __ATTR(monitor, S_IRUGO|S_IWUSR, show_monitor, store_monitor),
++};
++
++static int fsl_diu_probe(struct platform_device *pdev)
+ {
+- struct device_node *np = ofdev->node;
+ struct mfb_info *mfbi;
+- phys_addr_t dummy_ad_addr;
++ unsigned int dummy_ad_addr;
+ int ret, i, error = 0;
+- struct resource res;
+- struct fsl_diu_data *machine_data;
+
+- machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
+- if (!machine_data)
+- return -ENOMEM;
+-
+- for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
+- machine_data->fsl_diu_info[i] =
+- framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev);
+- if (!machine_data->fsl_diu_info[i]) {
+- dev_err(&ofdev->dev, "cannot allocate memory\n");
+- ret = -ENOMEM;
+- goto error2;
+- }
+- mfbi = machine_data->fsl_diu_info[i]->par;
+- memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
+- mfbi->parent = machine_data;
+- }
+-
+- ret = of_address_to_resource(np, 0, &res);
+- if (ret) {
+- dev_err(&ofdev->dev, "could not obtain DIU address\n");
+- goto error;
+- }
+- if (!res.start) {
+- dev_err(&ofdev->dev, "invalid DIU address\n");
+- goto error;
+- }
+- dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start);
++ DPRINTK("Entered: fsl_diu_probe\n");
+
+- dr.diu_reg = ioremap(res.start, sizeof(struct diu));
+- if (!dr.diu_reg) {
+- dev_err(&ofdev->dev, "Err: can't map DIU registers!\n");
+- ret = -EFAULT;
+- goto error2;
+- }
+-
+- out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU anyway*/
++ /* Area descriptor memory pool aligns to 64-bit boundary */
++ allocate_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
+
+- /* Get the IRQ of the DIU */
+- machine_data->irq = irq_of_parse_and_map(np, 0);
++ /* Get memory for Gamma Table - 32-byte aligned memory */
++ allocate_buf(&pool.gamma, 768, 32);
+
+- if (!machine_data->irq) {
+- dev_err(&ofdev->dev, "could not get DIU IRQ\n");
+- ret = -EINVAL;
+- goto error;
+- }
+- machine_data->monitor_port = monitor_port;
++ /* For high performance, cursor bitmap buffer aligns to 32-byte boundary */
++ allocate_buf(&pool.cursor, MAX_CURS * MAX_CURS * 4, 32);
+
+- /* Area descriptor memory pool aligns to 64-bit boundary */
+- if (allocate_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8))
+- return -ENOMEM;
++ /* Get memory for pallete table */
++ allocate_buf(&pool.pallete, 256 * 4, 32);
+
+- /* Get memory for Gamma Table - 32-byte aligned memory */
+- if (allocate_buf(&pool.gamma, 768, 32)) {
+- ret = -ENOMEM;
+- goto error;
+- }
+-
+- /* For performance, cursor bitmap buffer aligns to 32-byte boundary */
+- if (allocate_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32)) {
+- ret = -ENOMEM;
+- goto error;
+- }
+-
+- i = ARRAY_SIZE(machine_data->fsl_diu_info);
+- machine_data->dummy_ad = (struct diu_ad *)
+- ((u32)pool.ad.vaddr + pool.ad.offset) + i;
+- machine_data->dummy_ad->paddr = pool.ad.paddr +
+- i * sizeof(struct diu_ad);
+- machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);
+- if (!machine_data->dummy_aoi_virt) {
+- ret = -ENOMEM;
+- goto error;
+- }
+- machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr);
+- machine_data->dummy_ad->pix_fmt = 0x88882317;
+- machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
+- machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2);
+- machine_data->dummy_ad->offset_xyi = 0;
+- machine_data->dummy_ad->offset_xyd = 0;
+- machine_data->dummy_ad->next_ad = 0;
+-
+- out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
+- out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);
+- out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);
+-
+- for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
+- machine_data->fsl_diu_info[i]->fix.smem_start = 0;
+- mfbi = machine_data->fsl_diu_info[i]->par;
++ i = sizeof(fsl_diu_info) / sizeof(struct fb_info);
++ dummy_ad = (struct diu_ad *)((u32)pool.ad.vaddr + pool.ad.offset) + i;
++ dummy_ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad);
++ dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);
++ dummy_ad->addr = cpu_to_le32(dummy_ad_addr);
++ dummy_ad->pix_fmt = 0x88882317;
++ dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4); /* alpha = 0 */
++ dummy_ad->aoi_size = cpu_to_le32(( 4 << 16) | 2);
++ dummy_ad->offset_xyi = 0;
++ dummy_ad->offset_xyd = 0;
++ dummy_ad->next_ad = 0;
++ memset(dummy_aoi_virt, 0x00, 64);
++ write_reg(&(dr.diu_reg->desc[0]), dummy_ad->paddr);
++ write_reg(&(dr.diu_reg->desc[1]), dummy_ad->paddr);
++ write_reg(&(dr.diu_reg->desc[2]), dummy_ad->paddr);
++
++ for (i = 0; i < sizeof(fsl_diu_info) / sizeof(struct fb_info); i++) {
++ fsl_diu_info[i].fix.smem_start = 0;
++ mfbi = (struct mfb_info *)fsl_diu_info[i].par;
+ mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr
+ + pool.ad.offset) + i;
+ mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad);
+- ret = install_fb(machine_data->fsl_diu_info[i]);
+- if (ret) {
+- dev_err(&ofdev->dev,
+- "Failed to register framebuffer %d\n",
+- i);
+- goto error;
++ if ((ret = install_fb(&fsl_diu_info[i], pdev))) {
++ printk("Failed to register framebuffer %d\n", i);
++ return ret;
+ }
+ }
++ mfbi = (struct mfb_info *)fsl_diu_info[0].par;
++ init_waitqueue_head(&mfbi->vsync.wait);
+
+- if (request_irq_local(machine_data->irq)) {
+- dev_err(machine_data->fsl_diu_info[0]->dev,
+- "could not request irq for diu.");
+- goto error;
++ for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
++ error = device_create_file(fsl_diu_info[0].dev, &device_attrs[i]);
++
++ if (error)
++ break;
+ }
+
+- machine_data->dev_attr.attr.name = "monitor";
+- machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
+- machine_data->dev_attr.show = show_monitor;
+- machine_data->dev_attr.store = store_monitor;
+- error = device_create_file(machine_data->fsl_diu_info[0]->dev,
+- &machine_data->dev_attr);
+ if (error) {
+- dev_err(machine_data->fsl_diu_info[0]->dev,
+- "could not create sysfs %s file\n",
+- machine_data->dev_attr.attr.name);
++ while (--i >= 0)
++ device_remove_file(fsl_diu_info[0].dev, &device_attrs[i]);
+ }
+
+- dev_set_drvdata(&ofdev->dev, machine_data);
++#if defined(CONFIG_NOT_COHERENT_CACHE)
++ coherence_data = fsl_diu_alloc(32*1024, &coherence_data_phy);
++#endif
++
++ request_irq_local();
+ return 0;
++}
+
+-error:
+- for (i = ARRAY_SIZE(machine_data->fsl_diu_info);
+- i > 0; i--)
+- uninstall_fb(machine_data->fsl_diu_info[i - 1]);
+- if (pool.ad.vaddr)
+- free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
+- if (pool.gamma.vaddr)
+- free_buf(&pool.gamma, 768, 32);
+- if (pool.cursor.vaddr)
+- free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32);
+- if (machine_data->dummy_aoi_virt)
+- fsl_diu_free(machine_data->dummy_aoi_virt, 64);
+- iounmap(dr.diu_reg);
++static struct platform_device fsl_diu_device = {
++ .name = "fsl_diu",
++};
+
+-error2:
+- for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
+- if (machine_data->fsl_diu_info[i])
+- framebuffer_release(machine_data->fsl_diu_info[i]);
+- kfree(machine_data);
+
+- return ret;
+-}
+
++int __init fsl_diu_init(void)
++{
++ struct device_node *np;
++ struct resource r;
++ int error;
++ DPRINTK("Entered: fsl_diu_init\n");
++
++ np = of_find_compatible_node(NULL, NULL, "fsl-diu");
++ if(!np) {
++ printk("Err: can't find device node 'fsl-diu'\n");
++ return -ENODEV;
++ }
++
++ of_address_to_resource(np, 0, &r);
++ of_node_put(np);
++
++ DPRINTK("%s, r.start: 0x%08x\n", __func__, r.start);
+
+-static int fsl_diu_remove(struct of_device *ofdev)
++ dr.diu_reg = (struct diu *)ioremap(r.start, sizeof(struct diu));
++
++ write_reg(&(dr.diu_reg->diu_mode), 0); /* disable DIU anyway */
++
++ spin_lock_init(&dr.reg_lock);
++
++
++ /*
++ * For kernel boot options (in 'video=xxxfb:<options>' format)
++ */
++#ifndef MODULE
++ {
++ char *option;
++
++ if (fb_get_options("fslfb", &option))
++ return -ENODEV;
++ fsl_diu_setup(option);
++ }
++#endif
++ error = platform_driver_register(&fsl_diu_driver);
++
++ if (!error) {
++ error = platform_device_register(&fsl_diu_device);
++ if (error) {
++ printk("Err: can't register FB device driver!\n");
++ platform_driver_unregister(&fsl_diu_driver);
++ }
++ printk("FSL_DIU_FB: registed FB device driver!\n");
++ }
++
++ return error;
++}
++
++void __exit fsl_diu_exit(void)
+ {
+- struct fsl_diu_data *machine_data;
+ int i;
+
+- machine_data = dev_get_drvdata(&ofdev->dev);
+- disable_lcdc(machine_data->fsl_diu_info[0]);
+- free_irq_local(machine_data->irq);
+- for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--)
+- uninstall_fb(machine_data->fsl_diu_info[i - 1]);
+- if (pool.ad.vaddr)
+- free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
+- if (pool.gamma.vaddr)
+- free_buf(&pool.gamma, 768, 32);
+- if (pool.cursor.vaddr)
+- free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32);
+- if (machine_data->dummy_aoi_virt)
+- fsl_diu_free(machine_data->dummy_aoi_virt, 64);
++ DPRINTK("Entered: fsl_diu_exit\n");
++ free_irq_local();
++ for (i = sizeof(fsl_diu_info) / sizeof(struct fb_info); i > 0; i--)
++ uninstall_fb(&fsl_diu_info[i - 1]);
++
++ platform_driver_unregister(&fsl_diu_driver);
+ iounmap(dr.diu_reg);
+- for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
+- if (machine_data->fsl_diu_info[i])
+- framebuffer_release(machine_data->fsl_diu_info[i]);
+- kfree(machine_data);
+
+- return 0;
++ free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
++ free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 4, 32);
++ fsl_diu_free(dummy_aoi_virt,64);
++ return;
+ }
+
+ #ifndef MODULE
+ static int __init fsl_diu_setup(char *options)
+ {
+ char *opt;
+- unsigned long val;
++ int val;
+
++ DPRINTK("Entered: fsl_diu_setup\n");
+ if (!options || !*options)
+ return 0;
+
+@@ -1613,12 +1856,14 @@
+ if (!*opt)
+ continue;
+ if (!strncmp(opt, "monitor=", 8)) {
+- if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2))
++ val = simple_strtoul (opt + 8, NULL, 0);
++ if ((val == 0 ) || (val == 1) || (val == 2))
+ monitor_port = val;
+- } else if (!strncmp(opt, "bpp=", 4)) {
+- if (!strict_strtoul(opt + 4, 10, &val))
+- default_bpp = val;
+- } else
++ } else if (!strncmp(opt, "hwcursor=", 9)) {
++ hwcursor = simple_strtoul(opt + 9, NULL, 0);
++ } else if (!strncmp(opt, "bpp=", 4))
++ default_bpp = simple_strtoul(opt + 4, NULL, 0);
++ else
+ fb_mode = opt;
+ }
+
+@@ -1626,107 +1871,16 @@
+ }
+ #endif
+
+-static struct of_device_id fsl_diu_match[] = {
+- {
+- .compatible = "fsl,diu",
+- },
+- {}
+-};
+-MODULE_DEVICE_TABLE(of, fsl_diu_match);
+-
+-static struct of_platform_driver fsl_diu_driver = {
+- .owner = THIS_MODULE,
+- .name = "fsl_diu",
+- .match_table = fsl_diu_match,
+- .probe = fsl_diu_probe,
+- .remove = fsl_diu_remove,
+- .suspend = fsl_diu_suspend,
+- .resume = fsl_diu_resume,
+-};
+-
+-static int __init fsl_diu_init(void)
+-{
+-#ifdef CONFIG_NOT_COHERENT_CACHE
+- struct device_node *np;
+- const u32 *prop;
+-#endif
+- int ret;
+-#ifndef MODULE
+- char *option;
+-
+- /*
+- * For kernel boot options (in 'video=xxxfb:<options>' format)
+- */
+- if (fb_get_options("fslfb", &option))
+- return -ENODEV;
+- fsl_diu_setup(option);
+-#endif
+- printk(KERN_INFO "Freescale DIU driver\n");
+-
+-#ifdef CONFIG_NOT_COHERENT_CACHE
+- np = of_find_node_by_type(NULL, "cpu");
+- if (!np) {
+- printk(KERN_ERR "Err: can't find device node 'cpu'\n");
+- return -ENODEV;
+- }
+-
+- prop = of_get_property(np, "d-cache-size", NULL);
+- if (prop == NULL) {
+- of_node_put(np);
+- return -ENODEV;
+- }
+-
+- /* Freescale PLRU requires 13/8 times the cache size to do a proper
+- displacement flush
+- */
+- coherence_data_size = *prop * 13;
+- coherence_data_size /= 8;
+-
+- prop = of_get_property(np, "d-cache-line-size", NULL);
+- if (prop == NULL) {
+- of_node_put(np);
+- return -ENODEV;
+- }
+- d_cache_line_size = *prop;
+-
+- of_node_put(np);
+- coherence_data = vmalloc(coherence_data_size);
+- if (!coherence_data)
+- return -ENOMEM;
+-#endif
+- ret = of_register_platform_driver(&fsl_diu_driver);
+- if (ret) {
+- printk(KERN_ERR
+- "fsl-diu: failed to register platform driver\n");
+-#if defined(CONFIG_NOT_COHERENT_CACHE)
+- vfree(coherence_data);
+-#endif
+- iounmap(dr.diu_reg);
+- }
+- return ret;
+-}
+-
+-static void __exit fsl_diu_exit(void)
+-{
+- of_unregister_platform_driver(&fsl_diu_driver);
+-#if defined(CONFIG_NOT_COHERENT_CACHE)
+- vfree(coherence_data);
+-#endif
+-}
+-
+ module_init(fsl_diu_init);
+ module_exit(fsl_diu_exit);
+
+-MODULE_AUTHOR("York Sun <yorksun@freescale.com>");
+-MODULE_DESCRIPTION("Freescale DIU framebuffer driver");
+-MODULE_LICENSE("GPL");
++EXPORT_SYMBOL(fsl_diu_register_client);
++EXPORT_SYMBOL(fsl_diu_unregister_client);
+
+-module_param_named(mode, fb_mode, charp, 0);
+-MODULE_PARM_DESC(mode,
+- "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
+-module_param_named(bpp, default_bpp, ulong, 0);
+-MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
+-module_param_named(monitor, monitor_port, int, 0);
+-MODULE_PARM_DESC(monitor,
+- "Specify the monitor port (0, 1 or 2) if supported by the platform");
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("FSL DIU framebuffer driver");
++MODULE_LICENSE("GPL");
+
++module_param(hwcursor, int, 0644);
++MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
++ "(1=enable, 0=disable, default=1)");
+diff -Naur linux-2.6.29/drivers/video/fsl-diu-fb.h linux-2.6.29-v2010041601/drivers/video/fsl-diu-fb.h
+--- linux-2.6.29/drivers/video/fsl-diu-fb.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/video/fsl-diu-fb.h 2010-04-13 20:23:26.000000000 +0200
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright 2007,2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale DIU Frame Buffer device driver
+ *
+@@ -7,6 +7,7 @@
+ * Paul Widmer <paul.widmer@freescale.com>
+ * Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
+ * York Sun <yorksun@freescale.com>
++ * Copyright (C) Freescale Semicondutor, Inc. 2007. All rights reserved.
+ *
+ * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
+ *
+@@ -20,6 +21,16 @@
+ #ifndef __FSL_DIU_FB_H__
+ #define __FSL_DIU_FB_H__
+
++/* FIXME: This should be changed to dev_dbg this will be done as soon as
++ * we can obtain dev through the dts setup
++ */
++
++#ifdef DEBUG
++#define DPRINTK(fmt, args...) printk("%s: " fmt,__FUNCTION__,## args)
++#else
++#define DPRINTK(fmt, args...)
++#endif
++
+ /* Arbitrary threshold to determine the allocation method
+ * See mpc8610fb_set_par(), map_video_memory(), and unmap_video_memory()
+ */
+@@ -30,6 +41,8 @@
+ */
+ #define MIN_PIX_CLK 5629
+ #define MAX_PIX_CLK 96096
++#define MFB_PALETTE_ENTRIES 256
++#define OUT_DISP_AREA 2000
+
+ #include <linux/types.h>
+
+@@ -53,23 +66,475 @@
+ int y_aoi_d;
+ };
+
+-#define MFB_SET_CHROMA_KEY _IOW('M', 1, struct mfb_chroma_key)
+ #define MFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t)
+ #define MFB_SET_BRIGHTNESS _IOW('M', 3, __u8)
+
++#define MFB_SET_CHROMA_KEY 0x80024d00
++#define MFB_GET_CHROMA_KEY 0x40024d00
+ #define MFB_SET_ALPHA 0x80014d00
+ #define MFB_GET_ALPHA 0x40014d00
+ #define MFB_SET_AOID 0x80084d04
+ #define MFB_GET_AOID 0x40084d04
+-#define MFB_SET_PIXFMT 0x80014d08
+-#define MFB_GET_PIXFMT 0x40014d08
++#define MFB_SET_BYTE_FLIP 0x80044d00
+
+ #define FBIOGET_GWINFO 0x46E0
+ #define FBIOPUT_GWINFO 0x46E1
++#define MFB_SET_GAMMA 0x80014d01
++#define MFB_GET_GAMMA 0x40014d01
+
+ #ifdef __KERNEL__
+ #include <linux/spinlock.h>
++#define PANEL_TYPE_800x600_42 1
++#define PANEL_TYPE_640x480_60 2
++#define PANEL_TYPE_1024x768_26 3
++#define PANEL_TYPE_DEFAULT 4
++#define PANEL_TYPE_720x576_60 5
++#define PANEL_TYPE_720x480_60 6
++#define PANEL_TYPE_1280x720_50 7
++#define PANEL_TYPE_1280x720_60 8
++#define PANEL_TYPE_SELECT PANEL_TYPE_720x480_60
++
++/*
++ * These parameters give default parameters
++ * for video output 1024x768,
++ * FIXME - change timing to proper amounts
++ * hsync 31.5kHz, vsync 60Hz
++ */
++static struct fb_videomode __devinitdata fsl_diu_default_mode = {
++#if(PANEL_TYPE_SELECT==PANEL_TYPE_DEFAULT)
++ .refresh = 60,
++ .xres = 1024,
++ .yres = 768,
++ .pixclock = 15385,
++ .left_margin = 160,
++ .right_margin = 24,
++ .upper_margin = 29,
++ .lower_margin = 3,
++ .hsync_len = 136,
++ .vsync_len = 6,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_800x600_42)
++ .refresh = 42,
++ .xres = 800,
++ .yres = 600,
++ .pixclock =36849,
++ .left_margin = 112,
++ .right_margin = 112,
++ .upper_margin =16,
++ .lower_margin = 15,
++ .hsync_len =20 ,
++ .vsync_len =13,
++ .sync = 0,
++ //.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_640x480_60)
++ .refresh = 60,
++ .xres = 640,
++ .yres = 480,
++ .pixclock =39682,
++ .left_margin = 80,
++ .right_margin = 80,
++ .upper_margin =23,
++ .lower_margin = 22,
++ .hsync_len =20 ,
++ .vsync_len =13,
++ .sync = 0,
++ //.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_720x576_60)
++ .refresh = 50,
++ .xres = 720,
++ .yres = 576,
++ .pixclock =34557,
++ .left_margin = 106,
++ .right_margin = 80,
++ .upper_margin =15,
++ .lower_margin = 15,
++ .hsync_len =20 ,
++ .vsync_len =19,
++ .sync = 0,
++ //.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_1024x768_26)
++ .refresh = 26,
++ .xres = 1024,
++ .yres = 768,
++ .pixclock = 36644,
++ .left_margin = 144,
++ .right_margin = 144,
++ .upper_margin = 16,
++ .lower_margin = 16,
++ .hsync_len = 136,
++ .vsync_len = 6,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_720x480_60)
++ .refresh = 60,
++ .xres = 720,
++ .yres = 480,
++ .pixclock =37000,
++ .left_margin = 62,
++ .right_margin = 16,
++ .upper_margin =32,
++ .lower_margin = 10,
++ .hsync_len =60 ,
++ .vsync_len =3,
++ .sync = 0,
++ //.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_1280x720_50)
++ .refresh = 50,
++ .xres = 1280,
++ .yres = 720,
++ .pixclock = 13468,
++ .left_margin = 440,
++ .right_margin = 40,
++ .upper_margin = 5,
++ .lower_margin = 5,
++ .hsync_len = 220,
++ .vsync_len = 20,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++#elif(PANEL_TYPE_SELECT==PANEL_TYPE_1280x720_60)
++ .refresh = 60,
++ .xres = 1280,
++ .yres = 720,
++ .pixclock = 13468,
++ .left_margin = 40,
++ .right_margin = 110,
++ .upper_margin = 5,
++ .lower_margin = 5,
++ .hsync_len = 220,
++ .vsync_len = 20,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++#else
++#panel select failed
++#endif
++};
+
++static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
++ {
++ .name = "1280x720-60",
++ .refresh = 60,
++ .xres = 1280,
++ .yres = 720,
++ .pixclock = 13468,
++ .left_margin = 40,
++ .right_margin = 110,
++ .upper_margin = 5,
++ .lower_margin = 5,
++ .hsync_len = 220,
++ .vsync_len = 20,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "1280x720-50",
++ .refresh = 50,
++ .xres = 1280,
++ .yres = 720,
++ .pixclock = 13468,
++ .left_margin = 440,
++ .right_margin = 40,
++ .upper_margin = 5,
++ .lower_margin = 5,
++ .hsync_len = 220,
++ .vsync_len = 20,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "720x480-60",
++ .refresh = 60,
++ .xres = 720,
++ .yres = 480,
++ .pixclock =37000,
++ .left_margin = 62,
++ .right_margin = 16,
++ .upper_margin =32,
++ .lower_margin = 10,
++ .hsync_len =60 ,
++ .vsync_len =3,
++ .sync = 0,
++ //.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "640x480-60",
++ .refresh = 60,
++ .xres = 640,
++ .yres = 480,
++ .pixclock = 39722,
++ .left_margin = 48,
++ .right_margin = 16,
++ .upper_margin = 33,
++ .lower_margin = 10,
++ .hsync_len = 96,
++ .vsync_len = 2,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "640x480-72",
++ .refresh = 72,
++ .xres = 640,
++ .yres = 480,
++ .pixclock = 32052,
++ .left_margin = 128,
++ .right_margin = 24,
++ .upper_margin = 28,
++ .lower_margin = 9,
++ .hsync_len = 40,
++ .vsync_len = 3,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "640x480-75",
++ .refresh = 75,
++ .xres = 640,
++ .yres = 480,
++ .pixclock = 31747,
++ .left_margin = 120,
++ .right_margin = 16,
++ .upper_margin = 16,
++ .lower_margin = 1,
++ .hsync_len = 64,
++ .vsync_len = 3,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "640x480-90",
++ .refresh = 90,
++ .xres = 640,
++ .yres = 480,
++ .pixclock = 25057,
++ .left_margin = 120,
++ .right_margin = 32,
++ .upper_margin = 14,
++ .lower_margin = 25,
++ .hsync_len = 40,
++ .vsync_len = 14,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "640x480-100",
++ .refresh = 100,
++ .xres = 640,
++ .yres = 480,
++ .pixclock = 22272,
++ .left_margin = 48,
++ .right_margin = 32,
++ .upper_margin = 17,
++ .lower_margin = 22,
++ .hsync_len = 128,
++ .vsync_len = 12,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "800x600-60",
++ .refresh = 60,
++ .xres = 800,
++ .yres = 600,
++ .pixclock = 25000,
++ .left_margin = 88,
++ .right_margin = 40,
++ .upper_margin = 23,
++ .lower_margin = 1,
++ .hsync_len = 128,
++ .vsync_len = 4,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "1024x768-26",
++ .refresh = 26,
++ .xres = 1024,
++ .yres = 768,
++ .pixclock = 36644,
++ .left_margin = 144,
++ .right_margin = 144,
++ .upper_margin = 16,
++ .lower_margin = 16,
++ .hsync_len = 136,
++ .vsync_len = 6,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "640x480-60",
++ .refresh = 60,
++ .xres = 640,
++ .yres = 480,
++ .pixclock =39682,
++ .left_margin = 80,
++ .right_margin = 80,
++ .upper_margin =23,
++ .lower_margin = 22,
++ .hsync_len =20 ,
++ .vsync_len =13,
++ .sync = 0,
++ //.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "800x600-42",
++ .refresh = 42,
++ .xres = 800,
++ .yres = 600,
++ .pixclock =36849,
++ .left_margin = 112,
++ .right_margin = 112,
++ .upper_margin =16,
++ .lower_margin = 15,
++ .hsync_len =20 ,
++ .vsync_len =13,
++ .sync = 0,
++ //.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "720x576-60",
++ .refresh = 50,
++ .xres = 720,
++ .yres = 576,
++ .pixclock =34557,
++ .left_margin = 106,
++ .right_margin = 80,
++ .upper_margin =15,
++ .lower_margin = 15,
++ .hsync_len =20 ,
++ .vsync_len =19,
++ .sync = 0,
++ //.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "1024x768-60",
++ .refresh = 60,
++ .xres = 1024,
++ .yres = 768,
++ .pixclock = 15385,
++ .left_margin = 160,
++ .right_margin = 24,
++ .upper_margin = 29,
++ .lower_margin = 3,
++ .hsync_len = 136,
++ .vsync_len = 6,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "1024x768-70",
++ .refresh = 70,
++ .xres = 1024,
++ .yres = 768,
++ .pixclock = 16886,
++ .left_margin = 3,
++ .right_margin = 3,
++ .upper_margin = 2,
++ .lower_margin = 2,
++ .hsync_len = 40,
++ .vsync_len = 18,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "1024x768-75",
++ .refresh = 75,
++ .xres = 1024,
++ .yres = 768,
++ .pixclock = 15009,
++ .left_margin = 3,
++ .right_margin = 3,
++ .upper_margin = 2,
++ .lower_margin = 2,
++ .hsync_len = 80,
++ .vsync_len = 32,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "1280x1024-60",
++ .refresh = 60,
++ .xres = 1280,
++ .yres = 1024,
++ .pixclock = 9375,
++ .left_margin = 38,
++ .right_margin = 128,
++ .upper_margin = 2,
++ .lower_margin = 7,
++ .hsync_len = 216,
++ .vsync_len = 37,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "1280x1024-70",
++ .refresh = 70,
++ .xres = 1280,
++ .yres = 1024,
++ .pixclock = 9380,
++ .left_margin = 6,
++ .right_margin = 6,
++ .upper_margin = 4,
++ .lower_margin = 4,
++ .hsync_len = 60,
++ .vsync_len = 94,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "1280x1024-75",
++ .refresh = 75,
++ .xres = 1280,
++ .yres = 1024,
++ .pixclock = 9380,
++ .left_margin = 6,
++ .right_margin = 6,
++ .upper_margin = 4,
++ .lower_margin = 4,
++ .hsync_len = 60,
++ .vsync_len = 15,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "320x240", /* for AOI only */
++ .refresh = 60,
++ .xres = 320,
++ .yres = 240,
++ .pixclock = 15385,
++ .left_margin = 0,
++ .right_margin = 0,
++ .upper_margin = 0,
++ .lower_margin = 0,
++ .hsync_len = 0,
++ .vsync_len = 0,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++ {
++ .name = "1280x480-60",
++ .refresh = 60,
++ .xres = 1280,
++ .yres = 480,
++ .pixclock = 18939,
++ .left_margin = 353,
++ .right_margin = 47,
++ .upper_margin = 39,
++ .lower_margin = 4,
++ .hsync_len = 8,
++ .vsync_len = 2,
++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++ .vmode = FB_VMODE_NONINTERLACED
++ },
++};
+ /*
+ * These are the fields of area descriptor(in DDR memory) for every plane
+ */
+@@ -85,10 +550,10 @@
+ /* __u16 byte_f:1; */
+ /* __u16 res0:3; */
+
+- __be32 pix_fmt; /* hard coding pixel format */
++ __u32 pix_fmt; /* hard coding pixel format */
+
+ /* Word 1(32-bit) in DDR memory */
+- __le32 addr;
++ __u32 addr;
+
+ /* Word 2(32-bit) in DDR memory */
+ /* __u32 delta_xs:11; */
+@@ -96,7 +561,7 @@
+ /* __u32 delta_ys:11; */
+ /* __u32 res2:1; */
+ /* __u32 g_alpha:8; */
+- __le32 src_size_g_alpha;
++ __u32 src_size_g_alpha;
+
+ /* Word 3(32-bit) in DDR memory */
+ /* __u32 delta_xi:11; */
+@@ -104,7 +569,7 @@
+ /* __u32 delta_yi:11; */
+ /* __u32 res4:3; */
+ /* __u32 flip:2; */
+- __le32 aoi_size;
++ __u32 aoi_size;
+
+ /* Word 4(32-bit) in DDR memory */
+ /*__u32 offset_xi:11;
+@@ -112,35 +577,29 @@
+ __u32 offset_yi:11;
+ __u32 res6:5;
+ */
+- __le32 offset_xyi;
++ __u32 offset_xyi;
+
+ /* Word 5(32-bit) in DDR memory */
+ /*__u32 offset_xd:11;
+ __u32 res7:5;
+ __u32 offset_yd:11;
+ __u32 res8:5; */
+- __le32 offset_xyd;
++ __u32 offset_xyd;
+
+
+ /* Word 6(32-bit) in DDR memory */
+- __u8 ckmax_r;
+- __u8 ckmax_g;
+- __u8 ckmax_b;
+- __u8 res9;
++ __u32 ckmax_bgr;
+
+ /* Word 7(32-bit) in DDR memory */
+- __u8 ckmin_r;
+- __u8 ckmin_g;
+- __u8 ckmin_b;
+- __u8 res10;
++ __u32 ckmin_bgr;
+ /* __u32 res10:8; */
+
+ /* Word 8(32-bit) in DDR memory */
+- __le32 next_ad;
++ __u32 next_ad;
+
+ /* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
+ __u32 paddr;
+-} __attribute__ ((packed));
++}__attribute__ ((packed));
+
+ /* DIU register map */
+ struct diu {
+@@ -174,7 +633,7 @@
+ };
+
+ struct diu_addr {
+- __u8 __iomem *vaddr; /* Virtual address */
++ __u8 __iomem * vaddr; /* Virtual address */
+ dma_addr_t paddr; /* Physical address */
+ __u32 offset;
+ };
+@@ -186,11 +645,10 @@
+ struct diu_addr cursor;
+ };
+
+-#define FSL_DIU_BASE_OFFSET 0x2C000 /* Offset of DIU */
++#define FSL_DIU_BASE_OFFSET 0x2C000 /* Offset of Display Interface Unit(DIU) */
+ #define INT_LCDC 64 /* DIU interrupt number */
+
+-#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */
+- /* 1 for plane 0, 2 for plane 1&2 each */
++#define FSL_AOI_NUM 6 /* 5 AOIs (1 for plane 0, 2 for plane 1&2 each) and one dummy AOI */
+
+ /* Minimum X and Y resolutions */
+ #define MIN_XRES 64
+@@ -202,13 +660,13 @@
+ /* Modes of operation of DIU */
+ #define MFB_MODE0 0 /* DIU off */
+ #define MFB_MODE1 1 /* All three planes output to display */
+-#define MFB_MODE2 2 /* Plane 1 to display, planes 2+3 written back*/
++#define MFB_MODE2 2 /* Plane 1 to display, planes 2+3 written back to memory */
+ #define MFB_MODE3 3 /* All three planes written back to memory */
+ #define MFB_MODE4 4 /* Color bar generation */
+
+ /* INT_STATUS/INT_MASK field descriptions */
+-#define INT_VSYNC 0x01 /* Vsync interrupt */
+-#define INT_VSYNC_WB 0x02 /* Vsync interrupt for write back operation */
++#define INT_VSYNC 0x01 /* Vertical synchronize interrupt */
++#define INT_VSYNC_WB 0x02 /* Vertical synchronize interrupt for write back operation */
+ #define INT_UNDRUN 0x04 /* Under run exception interrupt */
+ #define INT_PARERR 0x08 /* Display parameters error interrupt */
+ #define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */
+@@ -219,5 +677,8 @@
+ #define MFB_TYPE_WB 2 /* Panel written back to memory */
+ #define MFB_TYPE_TEST 3 /* Panel generate color bar */
+
++void *fsl_diu_alloc(unsigned long size, dma_addr_t *phys);
++void fsl_diu_free(void *p, unsigned long size);
++
+ #endif /* __KERNEL__ */
+ #endif /* __FSL_DIU_FB_H__ */
+diff -Naur linux-2.6.29/drivers/video/Kconfig linux-2.6.29-v2010041601/drivers/video/Kconfig
+--- linux-2.6.29/drivers/video/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/video/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -1870,6 +1870,15 @@
+ ---help---
+ Framebuffer driver for the Freescale SoC DIU
+
++config FSL_DIU_FLIP_ON_VSYNC
++ bool "Flip buffers on VSYNC" if FB_FSL_DIU
++ default y
++ ---help---
++ Enable this if you want the fsl_diu_flip api to flip on vsync instead of
++ immediately.
++
++ If unsure, say Y.
++
+ config FB_W100
+ tristate "W100 frame buffer support"
+ depends on FB && ARCH_PXA
+diff -Naur linux-2.6.29/drivers/video/logo/logo_linux_clut224.ppm linux-2.6.29-v2010041601/drivers/video/logo/logo_linux_clut224.ppm
+--- linux-2.6.29/drivers/video/logo/logo_linux_clut224.ppm 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/drivers/video/logo/logo_linux_clut224.ppm 2010-04-13 20:23:26.000000000 +0200
+@@ -1,2828 +1,1604 @@
+ P3
+-145 113
++# Standard 224-color Linux logo
++80 80
+ 255
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 3 4 4 6 7 7
+-8 10 10 8 10 10 6 8 8 6 7 7 3 4 4 2 2 2
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 4 5 5 17 18 17
+-27 29 28 35 37 36 40 43 41 43 45 43 40 43 41 37 39 37
+-32 34 33 27 30 29 23 25 24 17 21 21 15 18 18 12 15 15
+-11 13 13 8 10 10 6 7 7 3 4 4 1 1 1 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 13 13 13 32 34 33 49 51 48 60 60 56 58 59 55
+-55 57 54 55 56 53 49 51 48 43 45 43 39 40 39 33 37 35
+-28 31 30 23 27 26 20 23 23 17 20 20 14 17 17 13 16 16
+-11 14 14 10 13 13 10 12 12 9 11 11 8 10 10 6 7 7
+-2 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 6 7 7 12 15 15
+-12 15 15 8 9 9 2 3 3 0 0 0 1 1 1 25 27 26
+-55 56 53 68 70 65 65 66 61 65 66 61 63 64 60 63 64 60
+-58 59 55 51 52 50 47 48 46 41 42 42 35 37 36 30 32 31
+-26 28 27 20 24 24 18 22 22 16 19 19 14 17 17 13 16 16
+-12 15 15 11 14 14 10 13 13 10 12 12 9 11 11 8 10 10
+-8 9 9 6 8 8 3 3 3 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 6 7 7 20 24 24 23 27 26
+-23 27 26 18 22 22 11 13 13 23 24 24 61 63 57 72 73 67
+-72 73 67 68 70 65 68 70 65 68 70 65 63 64 60 58 59 55
+-55 56 53 47 48 46 41 42 42 35 37 36 30 32 31 26 28 27
+-20 24 24 18 22 22 16 20 20 15 19 19 14 17 17 13 16 16
+-12 15 15 12 15 15 11 14 14 10 13 13 10 12 12 9 11 11
+-8 10 10 8 9 9 7 9 9 6 7 7 1 2 2 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 1 1 1 4 5 5 5 6 5 4 5 5
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 15 19 19 40 41 39 53 55 47
+-33 36 34 27 30 29 51 52 50 72 73 67 72 73 67 72 73 67
+-72 73 67 68 70 65 68 70 65 63 64 60 58 59 55 51 52 50
+-47 48 46 40 43 41 33 37 35 30 32 31 26 28 27 20 24 24
+-18 22 22 17 21 21 16 19 19 14 18 18 14 17 17 13 17 17
+-13 16 16 12 15 15 12 15 15 11 14 14 10 13 13 10 12 12
+-9 11 11 8 10 10 8 9 9 7 9 9 6 8 8 3 4 4
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-2 2 2 6 8 8 10 12 12 10 12 12 10 12 12 10 12 12
+-6 8 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 20 23 23 71 71 57 131 127 93
+-115 113 82 63 64 60 72 73 67 72 73 67 72 73 67 72 73 67
+-68 70 65 65 66 61 61 63 57 55 57 54 49 51 48 43 45 43
+-39 40 39 33 36 34 28 31 30 23 27 26 20 24 24 20 23 23
+-17 21 21 16 20 20 15 19 19 15 18 18 14 18 18 14 17 17
+-13 17 17 13 16 16 12 15 15 12 15 15 11 14 14 10 13 13
+-10 12 12 9 11 11 8 10 10 7 9 9 7 9 9 6 8 8
+-4 5 5 0 0 0 0 0 0 0 0 0 1 1 1 6 7 7
+-10 12 12 10 12 12 10 12 12 10 12 12 10 12 12 10 12 12
+-10 12 12 3 4 4 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 18 22 22 71 71 57 144 139 99
+-84 83 72 68 70 65 72 73 67 72 73 67 68 70 65 65 66 61
+-63 64 60 55 57 54 51 52 50 47 48 46 40 43 41 35 37 36
+-30 32 31 27 29 28 23 27 26 20 24 24 18 22 22 17 21 21
+-16 20 20 15 19 19 15 19 19 15 19 19 15 18 18 14 18 18
+-14 17 17 13 17 17 13 16 16 12 15 15 12 15 15 11 14 14
+-10 13 13 9 12 12 9 11 11 8 10 10 7 9 9 6 8 8
+-6 8 8 3 4 4 0 0 0 2 2 2 8 10 10 10 12 12
+-10 12 12 10 12 12 11 13 13 36 38 35 61 61 53 48 49 45
+-10 12 12 7 9 9 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 15 19 19 61 61 53 84 83 72
+-68 70 65 72 73 67 68 70 65 68 70 65 63 64 60 58 59 55
+-51 52 50 47 48 46 41 42 42 37 39 37 32 35 33 28 31 30
+-23 27 26 20 24 24 20 23 23 18 22 22 17 21 21 17 21 21
+-17 21 21 17 21 21 17 20 20 16 20 20 16 20 20 16 19 19
+-15 18 18 14 18 18 13 17 17 13 16 16 12 15 15 12 15 15
+-11 14 14 10 13 13 9 12 12 9 11 11 8 10 10 7 9 9
+-6 8 8 6 8 8 5 6 5 9 11 11 10 12 12 10 12 12
+-19 20 18 82 81 62 149 145 103 160 154 106 142 137 94 96 95 69
+-10 12 12 10 12 12 1 1 1 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 10 12 12 44 46 43 68 70 65
+-72 73 67 68 70 65 68 70 65 63 64 60 55 57 54 49 51 48
+-43 45 43 39 40 39 33 37 35 30 32 31 26 28 27 23 27 26
+-20 24 24 18 22 22 18 22 22 18 22 22 18 22 22 20 23 23
+-20 24 24 23 25 24 23 25 24 22 24 23 20 23 23 18 22 22
+-17 20 20 15 19 19 15 18 18 14 17 17 13 16 16 12 15 15
+-11 14 14 11 13 13 10 12 12 9 11 11 8 10 10 8 9 9
+-7 9 9 7 9 9 10 12 12 10 12 12 10 12 12 71 71 57
+-164 159 111 186 182 128 186 182 128 171 165 117 151 147 98 96 95 69
+-10 12 12 10 12 12 3 3 3 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 8 10 10 63 64 60 68 70 65
+-72 73 67 68 70 65 63 64 60 55 57 54 47 48 46 40 43 41
+-33 37 35 30 32 31 27 29 28 23 27 26 20 24 24 20 23 23
+-18 22 22 18 22 22 20 23 22 21 25 23 23 27 26 27 29 28
+-28 31 30 31 33 31 31 33 31 31 33 31 28 31 30 26 28 27
+-23 25 24 20 23 22 16 20 20 15 18 18 14 17 17 13 16 16
+-12 15 15 11 14 14 10 13 13 10 12 12 9 11 11 8 10 10
+-10 12 12 10 13 13 10 12 12 12 14 14 96 95 69 165 161 109
+-186 182 128 192 187 134 192 187 134 176 171 126 160 154 106 103 101 77
+-10 12 12 10 12 12 5 6 5 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 35 37 36 68 70 65 72 73 67
+-68 70 65 65 66 61 58 59 55 49 51 48 40 43 41 33 37 35
+-28 31 30 23 27 26 20 24 24 20 23 23 18 22 22 18 22 22
+-18 22 22 20 23 23 23 27 26 27 30 29 32 35 33 37 39 37
+-40 43 41 44 46 43 46 47 43 44 46 43 40 43 41 36 38 35
+-31 33 31 27 29 28 22 24 23 17 21 21 15 18 18 14 17 17
+-13 16 16 12 15 15 11 14 14 11 14 14 11 13 13 13 16 16
+-13 16 16 11 14 14 10 12 12 79 78 62 142 137 94 164 159 111
+-178 174 128 192 187 134 192 187 134 176 171 126 160 154 106 96 95 69
+-10 12 12 10 12 12 6 7 7 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 55 57 54 68 70 65 72 73 67
+-68 70 65 63 64 60 55 56 53 43 45 43 35 37 36 28 31 30
+-23 27 26 20 24 24 18 22 22 17 21 21 17 21 21 17 21 21
+-20 24 24 25 27 26 31 33 31 38 39 37 46 47 43 53 55 47
+-61 61 53 66 65 55 66 65 55 66 65 55 61 61 53 53 55 47
+-46 47 43 37 39 37 30 33 30 24 26 24 17 21 21 15 18 18
+-13 17 17 12 15 15 12 15 15 13 16 16 14 18 18 14 18 18
+-14 17 17 12 15 15 30 31 28 118 116 76 134 131 96 160 154 106
+-174 170 121 178 174 128 178 174 128 171 165 117 151 147 98 96 95 69
+-10 12 12 10 12 12 6 8 8 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 63 64 60 68 70 65 68 70 65
+-65 66 61 58 59 55 49 51 48 39 40 39 30 32 31 23 27 26
+-20 24 24 18 22 22 17 21 21 16 20 20 17 21 21 20 23 23
+-25 27 26 32 35 33 43 44 41 53 55 47 66 65 55 75 75 61
+-82 81 62 84 83 72 87 86 72 87 86 72 82 81 62 75 75 61
+-66 65 55 53 55 47 40 41 39 31 33 31 23 25 24 17 20 20
+-14 18 18 13 16 16 12 15 15 12 15 15 13 17 17 14 18 18
+-14 18 18 13 16 16 46 47 43 96 95 69 125 122 87 142 137 94
+-160 154 106 165 161 109 164 159 111 155 149 109 142 137 94 75 75 61
+-10 12 12 10 12 12 6 8 8 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 60 60 56 68 70 65 68 70 65
+-63 64 60 55 57 54 46 47 45 35 37 36 27 30 29 23 25 24
+-18 22 22 17 21 21 16 20 20 17 21 21 18 22 22 23 27 26
+-31 33 31 43 44 41 55 56 53 71 71 57 84 83 72 92 91 72
+-103 101 77 92 91 72 82 81 62 82 81 62 87 86 72 92 91 72
+-84 83 72 71 71 57 55 56 53 43 44 41 30 33 30 22 24 23
+-16 19 19 14 17 17 12 15 15 12 15 15 13 16 16 14 18 18
+-14 18 18 14 17 17 43 44 41 82 81 62 118 116 76 125 122 87
+-142 137 94 144 139 99 144 139 99 134 131 96 118 116 76 53 55 47
+-10 12 12 10 12 12 6 8 8 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 47 48 46 63 64 60 63 64 60
+-55 57 54 49 51 48 40 43 41 32 34 33 26 28 27 20 24 24
+-18 22 22 16 20 20 16 20 20 17 21 21 20 24 24 28 31 30
+-40 41 39 53 55 47 75 75 61 90 89 73 87 86 72 48 49 45
+-14 14 13 2 2 2 1 2 2 1 1 1 1 1 1 2 2 2
+-19 20 18 43 44 41 66 65 55 53 55 47 38 39 37 26 28 27
+-18 22 22 14 18 18 13 16 16 12 15 15 12 15 15 13 17 17
+-14 18 18 14 18 18 30 31 28 66 65 55 96 95 69 103 101 77
+-118 116 76 118 116 76 118 116 76 118 116 76 103 101 77 36 38 35
+-10 12 12 10 12 12 6 7 7 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 28 31 30 55 57 54 51 52 50
+-49 51 48 41 42 42 35 37 36 28 31 30 23 27 26 20 23 23
+-17 21 21 16 20 20 16 20 20 18 22 22 23 27 26 33 36 34
+-48 49 45 71 71 57 82 81 62 43 44 41 8 9 9 6 7 7
+-6 7 7 6 7 7 6 7 7 5 6 5 4 5 5 3 4 4
+-2 3 3 1 2 2 4 5 4 36 38 35 48 49 45 32 35 33
+-21 25 23 16 19 19 13 17 17 12 15 15 12 15 15 13 16 16
+-14 18 18 14 18 18 16 18 16 36 38 35 61 61 53 82 81 62
+-96 95 69 96 95 69 96 95 69 96 95 69 79 78 62 19 20 18
+-10 12 12 10 12 12 4 5 5 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 13 13 13 46 47 45 43 45 43
+-40 43 41 35 37 36 30 32 31 23 27 26 20 24 24 18 22 22
+-17 21 21 16 20 20 17 21 21 20 23 23 27 30 29 40 41 39
+-61 61 53 53 55 47 16 17 16 9 11 11 10 12 12 10 12 12
+-10 12 12 10 12 12 10 12 12 9 11 11 8 10 10 8 9 9
+-6 8 8 5 6 5 4 5 5 2 3 3 19 20 18 38 39 37
+-26 28 27 17 21 21 14 17 17 13 16 16 12 15 15 12 15 15
+-13 17 17 14 18 18 12 15 15 13 12 7 30 31 28 46 47 43
+-53 55 47 66 65 55 66 65 55 53 55 47 36 38 35 10 12 12
+-10 12 12 10 12 12 2 3 3 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 1 1 1 33 37 35 35 37 36
+-32 35 33 28 31 30 23 27 26 20 24 24 18 22 22 17 21 21
+-16 20 20 16 20 20 17 21 21 21 25 23 31 33 31 44 46 43
+-31 33 31 11 13 13 12 14 14 12 15 15 13 16 16 14 17 17
+-14 17 17 14 17 17 14 17 17 13 16 16 12 15 15 12 14 14
+-11 13 13 9 11 11 8 10 10 6 8 8 4 5 5 17 18 17
+-30 33 30 20 23 22 15 18 18 13 16 16 12 15 15 12 14 14
+-13 16 16 14 17 17 14 18 18 11 12 11 7 7 5 16 17 12
+-21 22 20 30 31 28 25 27 25 21 22 20 14 14 13 10 12 12
+-10 12 12 9 11 11 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 18 22 22 27 30 29
+-27 29 28 40 41 39 53 55 47 53 55 47 53 55 47 46 47 43
+-25 27 25 16 20 20 17 21 21 23 25 24 31 33 31 20 20 20
+-12 15 15 14 17 17 15 19 19 16 20 20 17 21 21 18 22 22
+-18 22 22 18 22 22 18 22 22 17 21 21 17 21 21 16 19 19
+-15 18 18 13 16 16 12 15 15 10 12 12 8 10 10 6 8 8
+-21 22 21 22 24 23 15 19 19 13 17 17 13 16 16 12 15 15
+-12 15 15 13 17 17 14 18 18 14 18 18 13 15 14 10 9 6
+-7 7 5 7 7 5 7 7 5 9 11 11 10 12 12 10 12 12
+-10 12 12 6 7 7 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 16 17 12 82 81 62
+-118 116 76 118 116 76 161 156 96 161 156 96 161 156 96 118 116 76
+-118 116 76 96 95 69 53 55 47 22 24 23 14 17 17 13 16 16
+-15 19 19 17 21 21 18 22 22 20 24 24 20 24 24 23 27 26
+-23 27 26 23 27 26 23 27 26 23 27 26 23 27 26 20 24 24
+-20 23 23 17 21 21 16 19 19 14 17 17 12 15 15 10 12 12
+-9 11 11 20 23 22 16 19 19 14 17 17 13 16 16 12 15 15
+-11 14 14 13 16 16 14 17 17 14 18 18 14 17 17 12 15 15
+-10 12 12 10 12 12 10 12 12 10 12 12 10 12 12 10 12 12
+-9 11 11 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 53 55 47 161 156 96
+-161 156 96 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 161 156 96 118 116 76 96 95 69 21 22 20 16 19 19
+-18 22 22 20 24 24 23 27 26 23 27 26 26 28 27 27 30 29
+-27 30 29 18 22 22 12 14 14 8 10 10 9 11 11 17 21 21
+-23 27 26 23 27 26 20 24 24 18 22 22 16 20 20 14 17 17
+-12 14 14 14 17 17 16 20 20 14 17 17 13 17 17 13 16 16
+-12 15 15 12 15 15 13 17 17 14 18 18 14 17 17 13 16 16
+-11 13 13 10 12 12 10 12 12 10 12 12 10 12 12 10 12 12
+-4 5 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 13 12 7 118 116 76 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 161 156 96 118 116 76 30 31 28
+-20 24 24 23 27 26 27 30 29 28 31 30 30 32 31 23 27 26
+-16 19 19 17 21 21 12 15 15 9 11 11 10 12 12 9 11 11
+-20 24 24 28 31 30 26 28 27 23 27 26 20 24 24 17 21 21
+-15 19 19 13 16 16 16 19 19 14 18 18 14 17 17 13 16 16
+-12 15 15 11 14 14 13 16 16 14 17 17 14 18 18 14 17 17
+-12 15 15 10 12 12 10 12 12 10 12 12 10 12 12 8 9 9
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 82 81 62 161 156 96 230 229 82
+-230 229 82 233 233 100 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 161 156 96 118 116 76
+-27 29 28 27 30 29 30 32 31 30 32 31 23 27 26 20 24 24
+-26 28 27 17 21 21 6 7 7 72 73 67 145 141 105 15 15 15
+-14 17 17 33 37 35 30 32 31 28 31 30 26 28 27 23 27 26
+-20 23 23 16 20 20 15 19 19 14 18 18 14 17 17 13 16 16
+-12 15 15 11 14 14 12 15 15 13 17 17 14 18 18 14 17 17
+-13 16 16 11 13 13 10 12 12 10 12 12 9 11 11 1 1 1
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 16 17 12 161 156 96 230 229 82 230 229 82
+-243 242 120 235 234 117 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 161 156 96
+-82 81 62 28 31 30 28 31 30 27 30 29 28 31 30 30 32 31
+-33 37 35 13 16 16 3 3 3 105 104 92 210 208 158 12 14 14
+-17 21 21 33 37 35 33 37 35 32 35 33 30 32 31 27 30 29
+-23 27 26 20 23 23 17 20 20 15 18 18 14 18 18 13 17 17
+-13 16 16 12 15 15 11 14 14 13 16 16 14 17 17 14 18 18
+-13 17 17 12 15 15 10 12 12 10 12 12 3 4 4 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 96 95 69 230 229 82 230 229 82 244 244 132
+-241 241 143 243 242 120 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-161 156 96 46 47 43 32 35 33 33 37 35 33 37 35 33 37 35
+-40 43 41 23 27 26 1 1 1 2 2 2 24 26 24 14 17 17
+-23 27 26 33 37 35 33 37 35 33 37 35 33 37 35 30 32 31
+-27 30 29 23 27 26 20 23 23 15 18 18 14 18 18 14 17 17
+-13 16 16 12 15 15 11 14 14 12 15 15 13 17 17 14 17 17
+-14 17 17 13 16 16 11 13 13 6 8 8 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 16 17 12 161 156 96 230 229 82 235 234 117 239 239 170
+-239 239 170 236 236 101 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 118 116 76 33 37 35 33 37 35 37 39 37 37 39 37
+-43 45 43 49 51 48 20 24 24 8 10 10 17 20 20 35 37 36
+-33 37 35 40 43 41 37 39 37 35 37 36 33 37 35 33 37 35
+-30 32 31 27 30 29 23 27 26 15 19 19 14 18 18 14 17 17
+-13 17 17 13 16 16 12 15 15 11 14 14 13 16 16 14 17 17
+-14 17 17 13 17 17 11 14 14 4 5 5 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 96 95 69 230 229 82 230 229 82 239 239 170 251 251 187
+-241 241 143 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 161 156 96 36 38 35 33 37 35 33 37 35 33 37 35
+-37 39 37 47 48 46 55 57 54 55 57 54 49 51 48 43 45 43
+-43 45 43 43 45 43 40 43 41 40 43 41 37 39 37 33 37 35
+-33 37 35 28 31 30 26 28 27 16 20 20 15 18 18 14 18 18
+-14 17 17 13 16 16 12 15 15 11 14 14 12 15 15 13 17 17
+-14 17 17 14 17 17 8 10 10 5 7 7 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-16 17 12 230 229 82 230 229 82 243 242 120 251 251 187 251 251 187
+-246 246 123 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 66 65 55 30 32 31 32 35 33 33 37 35
+-33 37 35 37 39 37 40 43 41 47 48 46 49 51 48 51 52 50
+-55 57 54 55 57 54 51 52 50 47 48 46 43 45 43 39 40 39
+-33 37 35 30 32 31 26 28 27 17 21 21 15 19 19 14 18 18
+-14 17 17 13 16 16 12 15 15 12 14 14 11 14 14 13 16 16
+-14 17 17 12 15 15 7 9 9 6 8 8 1 1 1 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-96 95 69 230 229 82 230 229 82 239 239 170 251 251 187 239 239 170
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 96 95 69 27 30 29 28 31 30 30 32 31
+-33 37 35 40 43 41 46 47 45 55 57 54 63 64 60 72 73 67
+-72 73 67 72 73 67 72 73 67 65 66 61 55 57 54 47 48 46
+-39 40 39 32 35 33 27 30 29 17 21 21 15 19 19 15 18 18
+-14 18 18 13 17 17 13 16 16 12 15 15 11 14 14 12 14 14
+-13 16 16 9 11 11 7 9 9 9 11 11 66 65 55 115 113 82
+-21 22 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 12 7
+-230 229 82 230 229 82 236 236 101 251 251 187 251 251 187 246 246 123
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 118 116 76 23 27 26 26 28 27 32 35 33
+-51 52 50 90 89 73 110 109 94 145 141 105 168 163 120 177 172 135
+-177 172 135 188 184 146 188 184 146 181 176 137 194 191 148 188 184 146
+-184 179 149 188 184 146 188 184 146 156 151 111 177 172 135 181 176 137
+-177 172 135 168 163 120 168 163 120 158 153 112 156 151 111 158 153 112
+-156 151 111 158 153 112 177 172 135 188 184 146 188 184 146 194 189 146
+-36 38 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 82 81 62
+-230 229 82 230 229 82 244 244 132 251 251 187 244 244 132 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 161 156 96 82 81 62
+-96 95 69 230 229 82 181 178 103 110 109 94 156 151 111 188 184 146
+-188 184 146 197 193 154 188 184 146 184 181 136 188 184 146 168 163 120
+-168 163 120 178 174 128 156 151 111 158 153 112 174 170 121 156 151 111
+-156 151 111 158 153 112 156 151 111 168 163 120 178 174 128 181 176 137
+-176 171 126 178 174 128 184 181 136 176 171 126 178 174 128 184 181 136
+-176 171 126 178 174 128 184 181 136 164 159 111 155 149 109 96 95 69
+-1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 161 156 96
+-230 229 82 230 229 82 244 244 132 244 244 132 236 236 101 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 46 47 43 82 81 62
+-158 153 112 197 193 154 194 189 146 184 181 136 188 184 146 168 163 120
+-156 151 111 137 133 100 131 127 93 137 133 100 137 133 100 158 153 112
+-121 119 87 137 133 100 156 151 111 145 141 105 99 98 80 84 83 72
+-63 64 60 52 53 49 40 43 41 33 36 34 36 38 35 36 38 35
+-38 39 37 43 44 41 43 44 41 46 47 43 48 49 45 48 49 45
+-46 47 43 36 38 35 30 31 28 19 20 18 6 7 7 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 36 38 35 230 229 82
+-230 229 82 230 229 82 246 246 123 236 236 101 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 53 55 47 121 119 87
+-176 171 126 171 165 117 161 156 96 82 81 62 53 55 47 33 37 35
+-39 40 39 63 64 60 99 98 80 121 119 87 137 133 100 177 172 135
+-176 171 126 184 181 136 131 127 93 131 127 93 110 109 94 84 83 72
+-51 52 50 39 40 39 27 29 28 18 22 22 16 19 19 15 19 19
+-15 19 19 14 18 18 14 17 17 13 16 16 12 15 15 11 14 14
+-10 13 13 9 12 12 9 11 11 8 9 9 7 9 9 1 1 1
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 118 116 76 230 229 82
+-230 229 82 230 229 82 236 236 101 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 96 95 69 71 71 57
+-36 38 35 118 116 76 118 116 76 12 15 15 15 18 18 20 24 24
+-33 37 35 55 56 53 84 83 72 110 109 94 145 141 105 110 109 94
+-168 163 120 121 119 87 156 151 111 131 127 93 87 86 72 61 63 57
+-47 48 46 28 31 30 18 22 22 15 19 19 15 18 18 15 19 19
+-15 19 19 14 18 18 14 17 17 13 17 17 13 16 16 12 15 15
+-11 13 13 10 12 12 9 11 11 8 10 10 7 9 9 3 3 3
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 1 1 0 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 161 156 96
+-161 156 96 230 229 82 118 116 76 11 14 14 14 17 17 18 22 22
+-27 30 29 40 43 41 60 60 56 84 83 72 105 104 92 110 109 94
+-110 109 94 110 109 94 99 98 80 90 89 73 68 70 65 47 48 46
+-32 34 33 23 25 24 20 23 23 17 21 21 15 19 19 14 17 17
+-15 19 19 15 18 18 14 18 18 13 17 17 13 16 16 12 15 15
+-11 14 14 10 12 12 9 11 11 8 10 10 7 9 9 4 5 5
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 16 17 12 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 161 156 96 118 116 76 11 13 13 13 16 16 15 19 19
+-20 24 24 30 32 31 40 43 41 51 52 50 63 64 60 72 73 67
+-65 66 61 65 66 61 65 66 61 55 57 54 46 47 45 33 37 35
+-27 29 28 20 24 24 17 21 21 16 20 20 16 20 20 15 19 19
+-15 19 19 15 19 19 14 18 18 14 17 17 13 16 16 12 15 15
+-11 14 14 10 13 13 9 12 12 8 10 10 7 9 9 6 7 7
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 53 55 47 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-161 156 96 118 116 76 53 55 47 10 13 13 12 15 15 14 17 17
+-17 20 20 20 24 24 27 29 28 32 34 33 37 39 37 40 43 41
+-43 45 43 41 42 42 35 37 36 30 32 31 28 31 30 23 27 26
+-20 23 23 17 21 21 16 20 20 16 20 20 16 20 20 16 19 19
+-15 19 19 15 19 19 14 18 18 14 17 17 13 16 16 12 15 15
+-11 14 14 10 13 13 9 12 12 9 11 11 8 10 10 10 12 12
+-1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 82 81 62 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 161 156 96 161 156 96
+-118 116 76 82 81 62 13 14 12 10 13 13 12 15 15 13 17 17
+-15 19 19 16 20 20 20 23 23 20 24 24 23 27 26 26 28 27
+-26 28 27 26 28 27 23 27 26 18 22 22 20 23 23 17 21 21
+-17 21 21 16 20 20 16 20 20 16 20 20 16 20 20 16 19 19
+-15 19 19 15 19 19 15 18 18 14 17 17 13 17 17 13 16 16
+-12 15 15 12 14 14 12 14 14 12 14 14 12 14 14 23 24 24
+-6 8 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 118 116 76 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 161 156 96 161 156 96 118 116 76
+-71 71 57 13 14 12 9 12 12 10 13 13 12 15 15 13 17 17
+-15 18 18 15 19 19 16 20 20 17 21 21 17 21 21 18 22 22
+-18 22 22 18 22 22 17 21 21 16 19 19 15 18 18 14 18 18
+-16 19 19 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-15 19 19 15 19 19 15 18 18 14 18 18 16 20 20 23 25 24
+-17 21 21 25 27 26 47 48 46 47 48 46 51 52 50 72 73 67
+-33 36 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 118 116 76 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 161 156 96 118 116 76 118 116 76 46 47 43
+-9 11 11 9 11 11 10 12 12 11 13 13 12 15 15 14 17 17
+-15 18 18 15 19 19 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-15 19 19 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-15 19 19 16 20 20 20 24 24 55 56 53 32 34 33 84 83 72
+-90 89 73 110 109 94 110 109 94 105 104 92 110 109 94 110 109 94
+-72 73 67 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 96 95 69 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 161 156 96 118 116 76 82 81 62 16 17 12 9 11 11
+-9 11 11 9 12 12 10 13 13 12 14 14 13 16 16 14 18 18
+-15 19 19 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 19 19 33 36 34 99 98 80 156 151 111 145 141 105 184 179 149
+-168 163 120 184 179 149 177 172 135 156 151 111 145 141 105 110 109 94
+-90 89 73 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 71 71 57 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 230 229 82
+-230 229 82 161 156 96 230 229 82 230 229 82 230 229 82 161 156 96
+-118 116 76 82 81 62 30 31 28 9 11 11 9 11 11 9 11 11
+-10 12 12 10 13 13 11 14 14 13 16 16 14 17 17 15 18 18
+-15 19 19 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-18 22 22 58 59 55 137 133 100 197 193 154 214 212 158 210 208 158
+-197 193 154 184 179 149 184 179 149 137 133 100 110 109 94 99 98 80
+-84 83 72 10 10 9 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 16 17 12 230 229 82 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 230 229 82 161 156 96
+-161 156 96 161 156 96 161 156 96 161 156 96 118 116 76 71 71 57
+-21 22 20 12 14 14 11 13 13 10 12 12 10 12 12 10 13 13
+-11 13 13 12 15 15 13 16 16 14 17 17 14 18 18 15 19 19
+-16 20 20 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 20 20 16 20 20 16 20 20 16 20 20 17 21 21
+-23 27 26 84 83 72 184 179 149 251 251 187 210 208 158 184 179 149
+-184 179 149 156 151 111 110 109 94 84 83 72 63 64 60 51 52 50
+-18 22 22 6 8 8 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 118 116 76 230 229 82
+-230 229 82 230 229 82 230 229 82 230 229 82 161 156 96 161 156 96
+-161 156 96 161 156 96 118 116 76 53 55 47 20 23 22 16 19 19
+-13 16 16 12 15 15 12 14 14 11 14 14 11 14 14 11 14 14
+-12 15 15 13 16 16 14 17 17 15 19 19 16 20 20 17 21 21
+-23 27 26 18 22 22 20 24 24 23 27 26 30 32 31 17 21 21
+-16 20 20 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-23 27 26 33 37 35 137 133 100 156 151 111 158 153 112 105 104 92
+-105 104 92 68 70 65 39 40 39 18 22 22 12 14 14 12 15 15
+-9 11 11 4 5 5 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 16 17 12 230 229 82
+-230 229 82 230 229 82 230 229 82 161 156 96 118 116 76 118 116 76
+-118 116 76 66 65 55 43 45 43 32 34 33 25 27 26 20 23 22
+-17 20 20 15 18 18 14 17 17 15 18 18 13 16 16 14 17 17
+-14 18 18 16 20 20 32 34 33 55 57 54 58 59 55 72 73 67
+-105 104 92 55 57 54 65 66 61 63 64 60 40 43 41 33 37 35
+-41 42 42 20 24 24 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-17 21 21 26 28 27 30 32 31 35 37 36 68 70 65 39 40 39
+-23 27 26 15 18 18 13 16 16 11 14 14 9 12 12 8 10 10
+-7 9 9 6 7 7 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 36 38 35
+-230 229 82 230 229 82 230 229 82 96 95 69 30 31 28 49 51 48
+-90 89 73 68 70 65 55 57 54 47 48 46 47 48 46 43 45 43
+-32 34 33 43 45 43 43 45 43 23 27 26 25 27 26 40 43 41
+-40 43 41 90 89 73 110 109 94 145 141 105 156 151 111 156 151 111
+-184 179 149 184 179 149 177 172 135 184 179 149 137 133 100 84 83 72
+-105 104 92 63 64 60 49 51 48 47 48 46 28 31 30 18 22 22
+-16 20 20 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 15 19 19 15 19 19 15 19 19 18 22 22 15 19 19
+-13 16 16 12 15 15 11 14 14 10 13 13 9 12 12 9 11 11
+-8 10 10 6 8 8 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-30 31 28 230 229 82 71 71 57 2 2 1 0 0 0 58 59 55
+-105 104 92 84 83 72 65 66 61 84 83 72 110 109 94 110 109 94
+-145 141 105 105 104 92 110 109 94 110 109 94 84 83 72 110 109 94
+-158 153 112 197 193 154 197 193 154 239 239 170 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 251 251 187 210 208 158 197 193 154
+-197 193 154 184 179 149 145 141 105 137 133 100 105 104 92 47 48 46
+-20 23 23 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 19 19 15 19 19 15 19 19 14 18 18 14 17 17
+-13 17 17 13 16 16 12 14 14 12 14 14 13 13 13 13 13 13
+-13 13 13 12 12 12 10 10 9 6 7 7 2 2 2 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 65 66 61
+-105 104 92 84 83 72 84 83 72 110 109 94 184 179 149 210 208 158
+-210 208 158 210 208 158 214 212 158 197 193 154 214 212 158 210 208 158
+-251 251 187 251 251 187 251 251 187 251 251 187 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 251 251 187 251 251 187 251 251 187
+-251 251 187 251 251 187 239 239 170 251 251 187 184 179 149 84 83 72
+-26 28 27 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 20 20 15 19 19 15 19 19 15 18 18 14 18 18
+-13 17 17 13 16 16 15 15 15 14 14 13 14 14 13 14 14 13
+-13 13 13 13 13 13 12 12 12 12 12 12 12 12 12 3 4 4
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 72 73 67
+-105 104 92 99 98 80 84 83 72 99 98 80 177 172 135 197 193 154
+-251 251 187 251 251 187 251 251 187 251 251 187 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 251 251 187 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 251 251 187 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 214 212 158 197 193 154 99 98 80
+-23 27 26 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 20 20 15 19 19 15 19 19 15 18 18 14 18 18
+-14 17 17 16 16 16 16 16 16 16 16 16 15 15 15 14 14 13
+-14 14 13 13 13 13 13 13 13 12 12 12 12 12 12 12 12 12
+-3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 83 72
+-110 109 94 99 98 80 72 73 67 63 64 60 99 98 80 177 172 135
+-184 179 149 210 208 158 251 251 187 251 251 187 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 251 251 187 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 251 251 187 251 251 187 251 251 187
+-251 251 187 210 208 158 184 179 149 177 172 135 110 109 94 33 37 35
+-17 21 21 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-16 20 20 16 20 20 15 19 19 15 19 19 15 19 19 14 18 18
+-15 18 18 18 19 18 18 19 18 17 17 17 16 16 16 15 15 15
+-14 14 13 13 13 13 13 13 13 12 12 12 12 12 12 12 12 12
+-10 10 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 105 104 92
+-108 107 93 99 98 80 72 73 67 63 64 60 51 52 50 87 86 72
+-105 104 92 110 109 94 108 107 93 156 151 111 184 179 149 184 179 149
+-197 193 154 197 193 154 197 193 154 184 179 149 184 179 149 177 172 135
+-197 193 154 156 151 111 177 172 135 184 179 149 168 163 120 137 133 100
+-145 141 105 110 109 94 99 98 80 47 48 46 55 57 54 15 19 19
+-16 19 19 16 20 20 16 20 20 16 20 20 16 20 20 16 20 20
+-17 20 20 17 21 21 16 20 20 16 19 19 15 19 19 16 19 19
+-20 20 20 21 22 21 20 20 20 19 20 19 18 19 18 16 16 16
+-15 15 15 14 14 13 13 13 13 13 13 13 12 12 12 12 12 12
+-12 12 12 4 5 5 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 58 59 55 110 109 94
+-105 104 92 90 89 73 72 73 67 55 57 54 43 45 43 39 40 39
+-43 45 43 46 47 45 43 45 43 68 70 65 65 66 61 63 64 60
+-108 107 93 72 73 67 105 104 92 90 89 73 72 73 67 40 43 41
+-72 73 67 68 70 65 68 70 65 58 59 55 63 64 60 49 51 48
+-43 45 43 33 36 34 27 30 29 20 24 24 16 20 20 15 19 19
+-15 19 19 15 19 19 15 19 19 16 19 19 16 20 20 16 20 20
+-17 21 21 20 24 24 20 23 22 17 21 21 17 20 20 20 20 20
+-21 22 21 21 22 21 21 22 21 21 22 21 20 20 20 18 19 18
+-16 16 16 15 15 15 13 13 13 13 13 13 12 12 12 12 12 12
+-12 12 12 10 10 9 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 21 22 21 110 109 94 110 109 94
+-105 104 92 84 83 72 68 70 65 51 52 50 41 42 42 33 37 35
+-28 31 30 23 27 26 20 23 23 18 22 22 17 20 20 25 27 26
+-26 28 27 27 30 29 25 27 26 20 23 23 23 27 26 30 32 31
+-20 24 24 17 21 21 18 22 22 15 19 19 26 28 27 20 23 23
+-14 18 18 15 19 19 15 18 18 15 19 19 15 19 19 15 19 19
+-15 19 19 15 19 19 15 19 19 15 19 19 15 19 19 16 19 19
+-16 20 20 22 24 23 24 26 24 22 24 23 20 23 22 22 24 23
+-24 26 24 24 26 24 23 24 24 22 24 23 21 22 21 19 20 19
+-17 17 17 15 15 15 14 14 13 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 2 2 2 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 2 2 2 99 98 80 110 109 94 108 107 93
+-105 104 92 84 83 72 63 64 60 49 51 48 39 40 39 32 34 33
+-27 30 29 23 25 24 20 23 23 17 20 20 15 19 19 14 18 18
+-14 17 17 13 17 17 13 17 17 13 17 17 13 17 17 13 17 17
+-14 17 17 14 17 17 14 17 17 14 17 17 14 17 17 14 17 17
+-14 18 18 14 18 18 14 18 18 14 18 18 15 18 18 15 19 19
+-15 19 19 15 19 19 15 19 19 15 19 19 15 19 19 15 19 19
+-15 19 19 17 21 21 27 29 28 26 28 27 25 27 26 25 27 26
+-27 29 28 27 29 28 26 28 27 24 26 24 21 22 21 20 20 20
+-18 19 18 16 16 16 14 14 13 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 4 5 5 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 51 52 50 110 109 94 110 109 94 105 104 92
+-90 89 73 72 73 67 55 57 54 43 45 43 35 37 36 30 32 31
+-26 28 27 20 24 24 17 21 21 16 19 19 15 18 18 14 17 17
+-13 16 16 13 16 16 13 16 16 13 16 16 13 16 16 13 16 16
+-13 16 16 13 16 16 13 16 16 13 17 17 13 17 17 14 17 17
+-14 17 17 14 17 17 14 17 17 14 18 18 14 18 18 14 18 18
+-15 18 18 15 18 18 15 19 19 15 19 19 15 19 19 15 19 19
+-15 19 19 15 19 19 27 29 28 32 34 33 28 31 30 27 29 28
+-30 32 31 30 32 31 30 31 28 26 28 27 23 24 24 21 22 21
+-19 20 19 16 16 16 14 14 13 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 6 7 7 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 3 3 3 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 10 10 9 108 107 93 110 109 94 108 107 93 99 98 80
+-84 83 72 63 64 60 49 51 48 40 43 41 33 36 34 27 30 29
+-23 27 26 18 22 22 17 20 20 15 18 18 14 17 17 13 16 16
+-13 16 16 13 16 16 12 15 15 12 15 15 12 15 15 12 15 15
+-13 16 16 13 16 16 13 16 16 13 16 16 13 16 16 13 16 16
+-13 17 17 13 17 17 14 17 17 14 17 17 14 17 17 14 18 18
+-14 18 18 14 18 18 15 18 18 15 18 18 15 19 19 15 19 19
+-15 19 19 15 19 19 17 21 21 33 36 34 32 34 33 31 33 31
+-33 36 34 33 36 34 31 33 31 27 29 28 25 27 26 21 22 21
+-19 20 19 17 17 17 15 15 15 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 8 8 7 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 63 64 60 137 133 100 43 45 43 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 68 70 65 110 109 94 110 109 94 105 104 92 84 83 72
+-68 70 65 55 57 54 43 45 43 35 37 36 30 32 31 26 28 27
+-20 24 24 17 21 21 16 19 19 14 17 17 13 16 16 12 15 15
+-12 15 15 12 15 15 12 15 15 12 15 15 12 15 15 12 15 15
+-12 15 15 12 15 15 12 15 15 12 15 15 12 15 15 13 16 16
+-13 16 16 13 16 16 13 16 16 13 17 17 13 17 17 14 17 17
+-14 17 17 14 17 17 14 18 18 14 18 18 14 18 18 15 18 18
+-15 19 19 15 19 19 15 19 19 20 24 24 32 34 33 35 37 36
+-37 39 37 35 37 36 33 36 34 30 32 31 26 28 27 22 24 23
+-20 20 20 17 17 17 15 15 15 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 8 8 7 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-1 1 1 99 98 80 184 179 149 184 179 149 68 70 65 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-15 15 15 110 109 94 110 109 94 108 107 93 99 98 80 72 73 67
+-61 63 57 49 51 48 39 40 39 33 36 34 27 30 29 23 25 24
+-18 22 22 16 19 19 14 17 17 13 16 16 12 15 15 12 15 15
+-11 14 14 11 14 14 11 14 14 11 14 14 11 14 14 11 14 14
+-11 14 14 11 14 14 12 14 14 12 15 15 12 15 15 12 15 15
+-12 15 15 13 16 16 13 16 16 13 16 16 13 16 16 13 16 16
+-13 17 17 14 17 17 14 17 17 14 17 17 14 18 18 14 18 18
+-14 18 18 15 18 18 15 19 19 15 19 19 30 32 31 38 39 37
+-39 40 39 39 40 39 35 37 36 31 33 31 27 29 28 22 24 23
+-20 20 20 17 17 17 15 15 15 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 8 8 7 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3
+-110 109 94 197 193 154 210 208 158 184 179 149 68 70 65 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-68 70 65 110 109 94 110 109 94 105 104 92 84 83 72 65 66 61
+-51 52 50 43 45 43 35 37 36 30 32 31 25 27 26 20 23 23
+-17 20 20 15 18 18 13 16 16 12 15 15 12 15 15 11 14 14
+-11 14 14 11 14 14 11 13 13 11 13 13 11 13 13 11 13 13
+-11 14 14 11 14 14 11 14 14 11 14 14 11 14 14 11 14 14
+-12 15 15 12 15 15 12 15 15 12 15 15 13 16 16 13 16 16
+-13 16 16 13 16 16 13 17 17 13 17 17 14 17 17 14 17 17
+-14 18 18 14 18 18 14 18 18 16 19 19 37 39 37 41 42 42
+-41 42 42 41 42 42 38 39 37 32 34 33 27 29 28 23 24 24
+-21 22 21 17 17 17 15 15 15 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 8 8 7 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 11 11 11 137 133 100
+-197 193 154 251 251 187 239 239 170 184 179 149 31 33 31 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 12 12
+-110 109 94 110 109 94 105 104 92 90 89 73 72 73 67 58 59 55
+-46 47 45 37 39 37 31 33 31 26 28 27 20 24 24 17 21 21
+-15 18 18 13 16 16 12 15 15 12 14 14 11 13 13 11 13 13
+-10 13 13 10 13 13 10 13 13 10 13 13 10 13 13 10 13 13
+-10 13 13 10 13 13 11 13 13 11 13 13 11 14 14 11 14 14
+-11 14 14 11 14 14 12 14 14 12 15 15 12 15 15 12 15 15
+-13 16 16 13 16 16 13 16 16 13 16 16 13 17 17 13 17 17
+-14 17 17 14 17 17 14 18 18 23 27 26 41 42 42 41 42 42
+-43 45 43 41 42 42 39 40 39 33 36 34 27 29 28 23 24 24
+-21 22 21 17 17 17 15 15 15 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 6 7 7 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 27 29 28 168 163 120 210 208 158
+-251 251 187 251 251 187 210 208 158 137 133 100 1 1 1 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 60 56
+-110 109 94 105 104 92 105 104 92 84 83 72 65 66 61 51 52 50
+-40 43 41 33 36 34 27 30 29 23 25 24 18 22 22 16 19 19
+-14 17 17 12 15 15 11 14 14 11 14 14 10 13 13 10 13 13
+-10 13 13 10 12 12 10 12 12 10 12 12 10 12 12 10 12 12
+-10 12 12 10 12 12 10 13 13 10 13 13 10 13 13 11 13 13
+-11 13 13 11 14 14 11 14 14 11 14 14 11 14 14 12 15 15
+-12 15 15 12 15 15 12 15 15 13 16 16 13 16 16 13 16 16
+-13 17 17 13 17 17 14 17 17 32 34 33 43 45 43 43 45 43
+-43 45 43 43 45 43 39 40 39 33 36 34 27 29 28 23 24 24
+-21 22 21 17 17 17 15 15 15 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 6 7 7 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 1 1 1 68 70 65 184 179 149 210 208 158 251 251 187
+-251 251 187 214 212 158 184 179 149 37 39 37 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 6 7 7 105 104 92
+-105 104 92 105 104 92 99 98 80 72 73 67 58 59 55 46 47 45
+-35 37 36 30 32 31 25 27 26 20 23 23 16 19 19 14 17 17
+-12 15 15 12 14 14 11 13 13 10 13 13 10 12 12 10 12 12
+-10 12 12 10 12 12 9 12 12 9 12 12 9 12 12 9 12 12
+-10 12 12 10 12 12 10 12 12 10 12 12 10 12 12 10 13 13
+-10 13 13 10 13 13 11 13 13 11 13 13 11 14 14 11 14 14
+-11 14 14 12 15 15 12 15 15 12 15 15 12 15 15 13 16 16
+-13 16 16 13 16 16 17 20 20 41 42 42 46 47 45 46 47 45
+-46 47 45 43 45 43 40 41 39 33 36 34 27 29 28 23 24 24
+-20 20 20 17 17 17 15 15 15 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 4 5 5 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-15 15 15 110 109 94 197 193 154 214 212 158 251 251 187 251 251 187
+-239 239 170 184 179 149 84 83 72 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 47 48 46 105 104 92
+-105 104 92 99 98 80 84 83 72 68 70 65 51 52 50 40 43 41
+-32 34 33 27 29 28 22 24 23 17 21 21 15 18 18 13 16 16
+-12 15 15 11 13 13 10 13 13 10 12 12 9 12 12 9 12 12
+-9 12 12 9 12 12 9 11 11 9 11 11 9 11 11 9 11 11
+-9 12 12 9 12 12 9 12 12 9 12 12 10 12 12 10 12 12
+-10 12 12 10 12 12 10 13 13 10 13 13 10 13 13 11 13 13
+-11 14 14 11 14 14 11 14 14 12 14 14 12 15 15 12 15 15
+-12 15 15 13 16 16 28 31 30 43 45 43 47 48 46 47 48 46
+-47 48 46 43 45 43 40 41 39 33 36 34 27 29 28 22 24 23
+-20 20 20 17 17 17 15 15 15 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 3 4 4 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 60 60 56
+-177 172 135 197 193 154 251 251 187 251 251 187 251 251 187 251 251 187
+-184 179 149 110 109 94 3 4 4 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 1 1 1 99 98 80 105 104 92
+-99 98 80 87 86 72 84 83 72 63 64 60 46 47 45 35 37 36
+-30 32 31 25 27 26 18 22 22 16 19 19 14 17 17 12 15 15
+-11 14 14 10 13 13 9 12 12 9 12 12 9 11 11 9 11 11
+-9 11 11 9 11 11 9 11 11 9 11 11 9 11 11 9 11 11
+-9 11 11 9 11 11 9 11 11 9 11 11 9 12 12 9 12 12
+-9 12 12 10 12 12 10 12 12 10 12 12 10 13 13 10 13 13
+-10 13 13 11 13 13 11 14 14 11 14 14 11 14 14 12 15 15
+-12 15 15 14 17 17 41 42 42 47 48 46 49 51 48 51 52 50
+-47 48 46 43 45 43 40 41 39 33 36 34 27 29 28 22 24 23
+-19 20 19 16 16 16 14 14 13 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 2 2 2 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 23 24 24 137 133 100 184 179 149
+-210 208 158 251 251 187 251 251 187 251 251 187 251 251 187 184 179 149
+-110 109 94 13 13 13 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 30 32 31 105 104 92 99 98 80
+-84 83 72 84 83 72 72 73 67 55 57 54 41 42 42 32 34 33
+-27 29 28 20 24 24 17 20 20 14 17 17 13 16 16 12 14 14
+-10 13 13 10 12 12 9 11 11 9 11 11 9 11 11 9 11 11
+-9 11 11 9 11 11 9 11 11 9 11 11 9 11 11 9 11 11
+-9 11 11 9 11 11 9 11 11 9 11 11 9 11 11 9 11 11
+-9 11 11 9 12 12 9 12 12 10 12 12 10 12 12 10 12 12
+-10 13 13 10 13 13 10 13 13 11 13 13 11 14 14 11 14 14
+-11 14 14 27 29 28 55 56 53 72 73 67 51 52 50 51 52 50
+-49 51 48 43 45 43 39 40 39 32 34 33 26 28 27 21 22 21
+-19 20 19 16 16 16 18 19 17 13 13 13 12 12 12 12 12 12
+-12 12 12 12 12 12 1 1 1 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 8 8 7 84 83 72 184 179 149 197 193 154 251 251 187
+-251 251 187 251 251 187 251 251 187 251 251 187 184 179 149 145 141 105
+-19 20 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 14 14 13 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 72 73 67 105 104 92 84 83 72
+-72 73 67 84 83 72 68 70 65 49 51 48 39 40 39 30 32 31
+-25 27 26 18 22 22 15 18 18 13 16 16 12 15 15 11 13 13
+-10 12 12 9 11 11 9 11 11 9 11 11 9 11 11 9 11 11
+-9 11 11 9 11 11 9 11 11 9 11 11 9 11 11 9 11 11
+-9 11 11 9 11 11 9 11 11 9 11 11 9 11 11 9 11 11
+-9 11 11 9 11 11 9 11 11 9 12 12 9 12 12 9 12 12
+-10 12 12 10 12 12 10 12 12 10 13 13 10 13 13 11 13 13
+-13 16 16 41 42 42 99 98 80 158 153 112 65 66 61 51 52 50
+-49 51 48 43 45 43 39 40 39 31 33 31 25 27 26 21 22 21
+-21 22 21 68 70 65 55 56 53 13 13 13 12 12 12 12 12 12
+-12 12 12 11 11 11 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3
+-63 64 60 158 153 112 184 179 149 210 208 158 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 184 179 149 137 133 100 27 29 28
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-21 22 21 110 109 94 5 6 5 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 13 13 13 105 104 92 90 89 73 72 73 67
+-68 70 65 84 83 72 63 64 60 46 47 45 35 37 36 27 29 28
+-22 24 23 17 20 20 14 17 17 12 15 15 11 14 14 10 12 12
+-10 12 12 9 11 11 9 11 11 9 11 11 9 11 11 9 11 11
+-9 11 11 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 9 11 11 9 11 11 9 11 11 9 11 11 9 11 11
+-9 11 11 9 11 11 9 11 11 9 11 11 9 11 11 9 11 11
+-9 12 12 9 12 12 10 12 12 10 12 12 10 13 13 10 13 13
+-30 32 31 47 48 46 177 172 135 210 208 158 137 133 100 55 56 53
+-49 51 48 43 45 43 38 39 37 31 33 31 25 27 26 22 24 23
+-110 109 94 184 179 149 63 64 60 13 13 13 12 12 12 12 12 12
+-12 12 12 8 9 9 0 0 0 1 1 1 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 21 22 21 105 104 92
+-184 179 149 210 208 158 251 251 187 251 251 187 251 251 187 251 251 187
+-251 251 187 251 251 187 184 179 149 145 141 105 23 24 24 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-68 70 65 184 179 149 105 104 92 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 51 52 50 99 98 80 84 83 72 63 64 60
+-68 70 65 72 73 67 55 57 54 41 42 42 32 34 33 25 27 26
+-20 23 23 16 19 19 13 16 16 12 14 14 10 13 13 10 12 12
+-9 11 11 9 11 11 9 11 11 9 11 11 9 11 11 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 9 11 11 9 11 11
+-9 11 11 9 11 11 9 11 11 9 11 11 9 11 11 9 11 11
+-9 11 11 9 11 11 9 12 12 9 12 12 10 12 12 17 20 20
+-46 47 45 72 73 67 210 208 158 251 251 187 210 208 158 63 64 60
+-49 51 48 43 45 43 37 39 37 30 32 31 24 26 24 105 104 92
+-210 208 158 197 193 154 47 48 46 13 13 13 12 12 12 12 12 12
+-12 12 12 6 7 7 33 36 34 48 49 45 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 8 8 7 23 24 24 55 56 53 110 109 94
+-210 208 158 251 251 187 251 251 187 251 251 187 251 251 187 251 251 187
+-251 251 187 184 179 149 110 109 94 20 20 20 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-110 109 94 251 251 187 210 208 158 47 48 46 0 0 0 0 0 0
+-0 0 0 1 1 1 90 89 73 90 89 73 72 73 67 55 56 53
+-72 73 67 68 70 65 51 52 50 37 39 37 28 31 30 23 25 24
+-17 21 21 15 18 18 12 15 15 11 14 14 10 13 13 9 12 12
+-9 11 11 9 11 11 9 11 11 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 9 11 11 9 11 11 9 11 11 9 11 11 9 11 11
+-9 11 11 9 11 11 9 11 11 9 12 12 13 16 16 41 42 42
+-49 51 48 110 109 94 251 251 187 251 251 187 251 251 187 105 104 92
+-49 51 48 43 45 43 35 37 36 30 31 28 47 48 46 197 193 154
+-251 251 187 197 193 154 31 33 31 12 12 12 12 12 12 12 12 12
+-12 12 12 51 52 50 184 179 149 72 73 67 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2
+-11 11 11 21 22 21 30 32 31 40 41 39 60 60 56 145 141 105
+-251 251 187 251 251 187 251 251 187 251 251 187 251 251 187 214 212 158
+-184 179 149 110 109 94 13 13 13 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 4 5 4 61 61 53 48 49 45 3 4 3
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-156 151 111 251 251 187 251 251 187 184 179 149 11 11 11 0 0 0
+-0 0 0 26 28 27 99 98 80 84 83 72 60 60 56 43 45 43
+-72 73 67 65 66 61 49 51 48 35 37 36 27 29 28 20 24 24
+-17 20 20 14 17 17 12 15 15 11 13 13 10 12 12 9 11 11
+-9 11 11 9 11 11 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 9 11 11 9 11 11
+-9 11 11 9 11 11 9 11 11 11 13 13 37 39 37 47 48 46
+-51 52 50 184 179 149 251 251 187 251 251 187 251 251 187 145 141 105
+-47 48 46 41 42 42 35 37 36 27 29 28 137 133 100 251 251 187
+-251 251 187 197 193 154 19 20 19 12 12 12 12 12 12 12 12 12
+-27 29 28 184 179 149 214 212 158 63 64 60 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 1 1 1 6 7 7 16 16 16 24 26 24
+-30 32 31 38 39 37 47 48 46 55 57 54 68 70 65 110 109 94
+-197 193 154 251 251 187 251 251 187 251 251 187 210 208 158 184 179 149
+-105 104 92 8 8 7 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 65 66 61 184 179 149 156 151 111
+-30 32 31 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-168 163 120 251 251 187 251 251 187 251 251 187 110 109 94 0 0 0
+-0 0 0 60 60 56 84 83 72 68 70 65 51 52 50 38 39 37
+-84 83 72 63 64 60 43 45 43 33 36 34 25 27 26 20 23 22
+-15 18 18 13 16 16 12 14 14 10 13 13 9 12 12 9 11 11
+-9 11 11 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-9 11 11 9 11 11 10 12 12 33 36 34 46 47 45 51 52 50
+-72 73 67 210 208 158 251 251 187 251 251 187 251 251 187 177 172 135
+-47 48 46 41 42 42 35 37 36 37 39 37 184 179 149 251 251 187
+-251 251 187 197 193 154 13 13 13 12 12 12 12 12 12 12 12 12
+-110 109 94 251 251 187 251 251 187 37 39 37 0 0 0 0 0 0
+-0 0 0 21 22 20 2 2 1 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-4 5 5 12 12 12 21 22 21 25 27 26 30 32 31 38 39 37
+-46 47 45 55 56 53 60 60 56 65 66 61 68 70 65 105 104 92
+-110 109 94 197 193 154 210 208 158 197 193 154 184 179 149 84 83 72
+-2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 13 13 13 184 179 149 251 251 187
+-197 193 154 43 44 41 0 0 0 0 0 0 0 0 0 0 0 0
+-145 141 105 251 251 187 251 251 187 251 251 187 214 212 158 43 45 43
+-2 2 2 84 83 72 72 73 67 58 59 55 41 42 42 38 39 37
+-72 73 67 58 59 55 41 42 42 31 33 31 25 27 26 18 22 22
+-14 17 17 12 15 15 12 14 14 10 12 12 9 12 12 9 11 11
+-9 11 11 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 9 12 12 31 33 31 43 45 43 49 51 48 55 56 53
+-110 109 94 251 251 187 251 251 187 251 251 187 251 251 187 168 163 120
+-47 48 46 41 42 42 33 36 34 63 64 60 197 193 154 251 251 187
+-251 251 187 184 179 149 13 13 13 12 12 12 12 12 12 16 16 16
+-197 193 154 251 251 187 239 239 170 20 20 20 0 0 0 2 2 1
+-108 107 93 110 109 94 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 1 1 1 4 5 5 11 11 11 18 19 18
+-22 24 23 26 28 27 32 34 33 39 40 39 46 47 45 51 52 50
+-55 57 54 60 60 56 63 64 60 63 64 60 63 64 60 58 59 55
+-63 64 60 99 98 80 145 141 105 137 133 100 43 45 43 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 3 4 3 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 110 109 94 251 251 187
+-251 251 187 184 179 149 25 27 26 0 0 0 0 0 0 0 0 0
+-99 98 80 251 251 187 251 251 187 251 251 187 251 251 187 156 151 111
+-25 27 26 84 83 72 65 66 61 47 48 46 32 34 33 39 40 39
+-72 73 67 55 57 54 40 41 39 30 32 31 23 25 24 18 22 22
+-14 17 17 12 15 15 11 13 13 10 12 12 9 11 11 9 11 11
+-9 11 11 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-9 11 11 28 31 30 41 42 42 47 48 46 55 56 53 58 59 55
+-137 133 100 251 251 187 251 251 187 251 251 187 210 208 158 137 133 100
+-47 48 46 40 41 39 32 34 33 75 75 61 184 179 149 239 239 170
+-251 251 187 177 172 135 13 13 13 12 12 12 12 12 12 43 44 41
+-197 193 154 251 251 187 210 208 158 10 10 9 0 0 0 84 83 72
+-251 251 187 84 83 72 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
+-6 7 7 11 11 11 17 17 17 20 20 20 23 24 24 27 29 28
+-32 34 33 38 39 37 43 45 43 47 48 46 51 52 50 55 56 53
+-58 59 55 58 59 55 55 57 54 55 56 53 47 48 46 41 42 42
+-35 37 36 31 33 31 47 48 46 14 14 13 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 66 65 55 99 98 80 20 20 20
+-0 0 0 0 0 0 0 0 0 0 0 0 43 45 43 214 212 158
+-251 251 187 251 251 187 145 141 105 3 3 3 0 0 0 0 0 0
+-48 49 45 184 179 149 239 239 170 251 251 187 239 239 170 177 172 135
+-84 83 72 72 73 67 55 56 53 39 40 39 26 28 27 39 40 39
+-68 70 65 51 52 50 39 40 39 28 31 30 22 24 23 17 20 20
+-14 17 17 12 14 14 10 13 13 9 11 11 9 11 11 9 11 11
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-27 29 28 40 41 39 46 47 45 51 52 50 55 57 54 63 64 60
+-131 127 93 197 193 154 210 208 158 197 193 154 168 163 120 96 95 69
+-47 48 46 40 41 39 32 34 33 71 71 57 145 141 105 184 179 149
+-184 179 149 131 127 93 13 13 13 12 12 12 12 12 12 48 49 45
+-168 163 120 184 179 149 156 151 111 6 7 7 14 14 13 177 172 135
+-239 239 170 40 41 39 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 3 3 3 6 7 7 11 11 11 16 16 16
+-18 19 18 21 22 21 23 24 24 27 29 28 32 34 33 37 39 37
+-41 42 42 43 45 43 47 48 46 51 52 50 51 52 50 51 52 50
+-51 52 50 49 51 48 46 47 45 40 41 39 32 34 33 25 27 26
+-20 20 20 14 14 13 2 2 2 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 33 36 34 197 193 154 184 179 149
+-41 42 42 0 0 0 0 0 0 0 0 0 3 3 3 184 179 149
+-251 251 187 251 251 187 184 179 149 48 49 45 0 0 0 0 0 0
+-16 17 12 121 119 87 177 172 135 194 189 146 188 184 146 145 141 105
+-82 81 62 63 64 60 46 47 45 31 33 31 21 22 21 35 37 36
+-68 70 65 51 52 50 37 39 37 27 30 29 22 24 23 17 20 20
+-13 16 16 12 14 14 10 13 13 9 11 11 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 25 27 26
+-38 39 37 43 45 43 51 52 50 55 56 53 60 60 56 63 64 60
+-92 91 72 158 153 112 176 171 126 171 165 117 149 143 98 82 81 62
+-44 46 43 38 39 37 30 32 31 71 71 57 131 127 93 160 154 106
+-149 143 98 82 81 62 13 13 13 12 12 12 12 12 12 46 47 43
+-121 119 87 134 131 96 96 95 69 7 7 6 38 39 37 131 127 93
+-145 141 105 12 13 12 0 0 0 1 1 1 3 3 3 6 7 7
+-10 10 9 12 12 12 14 14 13 16 16 16 18 19 18 21 22 21
+-22 24 23 26 28 27 30 31 28 33 36 34 37 39 37 40 41 39
+-41 42 42 43 45 43 46 47 45 46 47 45 46 47 45 43 45 43
+-41 42 42 37 39 37 31 33 31 26 28 27 21 22 21 16 16 16
+-6 7 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 177 172 135 251 251 187
+-197 193 154 27 29 28 0 0 0 0 0 0 0 0 0 110 109 94
+-239 239 170 239 239 170 184 179 149 87 86 72 2 2 1 0 0 0
+-1 1 1 82 81 62 142 137 94 165 161 109 165 161 109 131 127 93
+-75 75 61 55 56 53 37 39 37 25 27 26 19 20 19 32 34 33
+-65 66 61 49 51 48 35 37 36 27 29 28 20 23 23 16 19 19
+-13 16 16 13 13 13 10 12 12 9 11 11 8 10 10 8 10 10
+-8 9 9 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 22 24 23 35 37 36
+-41 42 42 47 48 46 55 56 53 58 59 55 63 64 60 65 66 61
+-71 71 57 131 127 93 160 154 106 160 154 106 142 137 94 82 81 62
+-46 47 43 40 41 39 33 36 34 66 65 55 125 122 87 149 143 98
+-142 137 94 82 81 62 17 17 17 18 19 17 14 14 13 46 47 43
+-118 116 76 125 122 87 96 95 69 16 17 12 71 71 57 103 101 77
+-82 81 62 11 11 11 11 11 11 13 13 13 14 14 13 14 14 13
+-15 15 15 16 16 16 17 17 17 19 20 19 21 22 21 23 24 24
+-26 28 27 27 29 28 31 33 31 33 36 34 35 37 36 38 39 37
+-39 40 39 39 40 39 38 39 37 37 39 37 35 37 36 31 33 31
+-27 29 28 24 26 24 21 22 21 17 17 17 12 12 12 2 2 2
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 68 70 65 251 251 187
+-251 251 187 156 151 111 2 2 1 0 0 0 0 0 0 43 44 41
+-177 172 135 184 179 149 158 153 112 103 101 77 19 20 18 0 0 0
+-0 0 0 46 47 43 131 127 93 160 154 106 160 154 106 131 127 93
+-71 71 57 43 45 43 30 32 31 21 22 21 16 16 16 26 28 27
+-63 64 60 47 48 46 35 37 36 26 28 27 20 23 23 16 19 19
+-13 16 16 13 13 13 10 12 12 9 11 11 8 10 10 8 10 10
+-7 9 9 7 9 9 8 9 9 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 20 20 20 33 36 34 40 41 39
+-46 47 45 51 52 50 55 57 54 60 60 56 63 64 60 65 66 61
+-66 65 55 118 116 76 151 147 98 165 161 109 151 147 98 121 119 87
+-96 95 69 96 95 69 96 95 69 103 101 77 142 137 94 151 147 98
+-142 137 94 103 101 77 82 81 62 82 81 62 82 81 62 96 95 69
+-131 127 93 142 137 94 103 101 77 46 47 43 96 95 69 118 116 76
+-71 71 57 14 14 13 14 14 13 15 15 15 15 15 15 16 16 16
+-16 16 16 17 17 17 18 19 18 20 20 20 21 22 21 23 24 24
+-25 27 26 27 29 28 30 31 28 30 32 31 31 33 31 31 33 31
+-31 33 31 31 33 31 30 31 28 27 29 28 25 27 26 22 24 23
+-20 20 20 16 16 16 13 13 13 6 7 7 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-58 59 55 68 70 65 8 8 7 0 0 0 10 10 9 210 208 158
+-251 251 187 184 179 149 38 39 37 0 0 0 0 0 0 8 8 7
+-103 101 77 149 143 98 149 143 98 118 116 76 40 41 39 25 27 25
+-53 55 47 82 81 62 144 139 99 165 161 109 165 161 109 142 137 94
+-71 71 57 35 37 36 24 26 24 18 19 18 15 15 15 22 24 23
+-63 64 60 46 47 45 33 36 34 26 28 27 20 23 22 17 18 17
+-12 15 15 11 13 13 10 12 12 9 11 11 8 10 10 8 10 10
+-7 9 9 7 9 9 7 9 9 7 9 9 8 9 9 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 16 16 16 30 31 28 35 37 36 41 42 42
+-47 48 46 55 56 53 58 59 55 63 64 60 65 66 61 65 66 61
+-61 61 53 103 101 77 151 147 98 171 165 117 171 165 117 168 163 120
+-158 153 112 158 153 112 155 149 109 151 147 98 151 147 98 160 154 106
+-151 147 98 149 143 98 142 137 94 149 143 98 149 143 98 149 143 98
+-155 149 109 151 147 98 131 127 93 103 101 77 125 122 87 118 116 76
+-71 71 57 16 16 16 16 16 16 16 16 16 17 17 17 17 17 17
+-17 17 17 17 17 17 18 19 18 19 20 19 20 20 20 21 22 21
+-23 24 24 24 26 24 25 27 26 26 28 27 26 28 27 26 28 27
+-25 27 26 24 26 24 22 24 23 21 22 21 19 20 19 16 16 16
+-14 14 13 8 8 7 1 1 1 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-20 20 20 184 179 149 168 163 120 21 22 21 0 0 0 105 104 92
+-177 172 135 145 141 105 71 71 57 0 0 0 0 0 0 0 0 0
+-66 65 55 131 127 93 151 147 98 142 137 94 118 116 76 121 119 87
+-145 141 105 158 153 112 176 171 126 178 174 128 176 171 126 149 145 103
+-96 95 69 31 33 31 21 22 21 16 16 16 14 14 13 18 19 18
+-60 60 56 46 47 45 33 36 34 25 27 26 21 22 21 15 18 18
+-12 15 15 11 13 13 9 11 11 8 10 10 8 10 10 8 9 9
+-7 9 9 7 9 9 7 9 9 7 9 9 7 9 9 8 9 9
+-8 9 9 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 10 12 12 26 28 27 31 33 31 38 39 37 43 45 43
+-51 52 50 55 56 53 60 60 56 63 64 60 65 66 61 68 70 65
+-63 64 60 96 95 69 158 153 112 178 174 128 188 184 146 194 189 146
+-194 189 146 188 184 146 184 181 136 176 171 126 171 165 117 173 167 111
+-173 167 111 165 161 109 171 165 117 174 170 121 176 171 126 178 174 128
+-178 174 128 174 170 121 160 154 106 149 143 98 149 143 98 125 122 87
+-71 71 57 16 16 16 16 16 16 17 17 17 17 17 17 17 17 17
+-17 17 17 17 17 17 17 17 17 18 19 18 19 20 19 20 20 20
+-21 22 21 21 22 21 21 22 21 22 24 23 21 22 21 21 22 21
+-21 22 21 19 20 19 18 19 18 16 16 16 14 14 13 11 11 11
+-3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 105 104 92 197 193 154 110 109 94 9 9 8 36 38 35
+-121 119 87 131 127 93 96 95 69 18 19 17 30 31 28 66 65 55
+-96 95 69 142 137 94 160 154 106 160 154 106 160 154 106 168 163 120
+-184 181 136 194 191 148 197 193 154 197 193 154 194 189 146 168 163 120
+-125 122 87 46 47 43 18 19 18 15 15 15 13 13 13 14 14 13
+-55 57 54 43 45 43 32 34 33 25 27 26 18 22 22 17 17 17
+-12 14 14 10 12 12 9 11 11 8 10 10 8 9 9 7 9 9
+-6 8 8 7 9 9 7 9 9 7 9 9 7 9 9 7 9 9
+-7 9 9 8 9 9 8 9 9 8 10 10 8 10 10 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 32 34 33 41 42 42 35 37 36 39 40 39 37 39 37
+-35 37 36 55 57 54 60 60 56 63 64 60 65 66 61 65 66 61
+-61 63 57 115 113 82 168 163 120 194 191 148 204 201 155 210 208 158
+-210 208 158 210 208 158 197 193 154 194 189 146 186 182 128 176 171 126
+-174 170 121 176 171 126 186 182 128 190 186 136 194 191 148 197 193 154
+-197 193 154 188 184 146 181 176 137 174 170 121 165 161 109 142 137 94
+-82 81 62 24 26 24 16 16 16 16 16 16 16 16 16 16 16 16
+-17 17 17 17 17 17 17 17 17 17 17 17 18 19 18 19 20 19
+-19 20 19 19 20 19 20 20 20 19 20 19 19 20 19 18 19 18
+-17 17 17 15 15 15 13 13 13 12 12 12 6 7 7 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 17 18 17 137 133 100 115 113 82 53 55 47 19 20 18
+-103 101 77 144 139 99 137 133 100 115 113 82 137 133 100 156 151 111
+-158 153 112 164 159 111 171 165 117 174 170 121 178 174 128 194 189 146
+-204 201 155 214 212 158 214 212 158 214 212 158 210 208 158 188 184 146
+-158 153 112 87 86 72 17 17 17 13 13 13 13 13 13 15 15 15
+-55 56 53 43 45 43 32 34 33 24 26 24 17 20 20 16 16 16
+-12 14 14 10 12 12 8 10 10 8 10 10 7 9 9 6 8 8
+-6 8 8 6 8 8 6 8 8 7 9 9 7 9 9 7 9 9
+-7 9 9 7 9 9 7 9 9 7 9 9 8 9 9 8 10 10
+-8 10 10 8 10 10 8 10 10 8 10 10 8 10 10 8 10 10
+-8 10 10 110 109 94 84 83 72 49 51 48 26 28 27 8 10 10
+-8 9 9 51 52 50 58 59 55 63 64 60 63 64 60 63 64 60
+-66 65 55 134 131 96 181 176 137 210 208 158 214 212 158 239 239 170
+-239 239 170 224 223 159 210 208 158 204 201 155 194 189 146 186 182 128
+-186 182 128 184 181 136 194 189 146 204 201 155 210 208 158 210 208 158
+-210 208 158 210 208 158 197 193 154 190 186 136 176 171 126 155 149 109
+-118 116 76 36 38 35 15 15 15 16 16 16 16 16 16 16 16 16
+-16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 17 17 17
+-17 17 17 17 17 17 17 17 17 16 16 16 16 16 16 15 15 15
+-13 13 13 12 12 12 8 8 7 2 2 2 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 53 55 47 103 101 77 96 95 69 53 55 47
+-103 101 77 158 153 112 177 172 135 184 179 149 188 184 146 197 193 154
+-194 189 146 190 186 136 184 181 136 184 181 136 194 189 146 210 208 158
+-214 212 158 239 239 170 251 251 187 251 251 187 224 223 159 204 201 155
+-177 172 135 121 119 87 30 31 28 13 13 13 12 12 12 39 40 39
+-60 60 56 43 45 43 32 34 33 23 25 24 18 19 18 13 16 16
+-13 13 13 9 11 11 8 10 10 8 9 9 6 8 8 6 8 8
+-6 8 8 6 8 8 6 8 8 6 8 8 6 8 8 7 9 9
+-7 9 9 7 9 9 7 9 9 7 9 9 7 9 9 7 9 9
+-7 9 9 8 9 9 8 9 9 8 10 10 8 10 10 8 10 10
+-14 17 17 197 193 154 158 153 112 55 57 54 7 9 9 7 9 9
+-8 10 10 51 52 50 58 59 55 60 60 56 63 64 60 63 64 60
+-71 71 57 155 149 109 194 191 148 214 212 158 251 251 187 251 251 187
+-251 251 187 251 251 187 239 239 170 210 208 158 197 193 154 190 186 136
+-190 186 136 194 189 146 204 201 155 210 208 158 224 223 159 239 239 170
+-239 239 170 224 223 159 210 208 158 204 201 155 190 186 136 164 159 111
+-125 122 87 40 41 39 15 15 15 15 15 15 15 15 15 15 15 15
+-16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16
+-16 16 16 16 16 16 15 15 15 14 14 13 13 13 13 12 12 12
+-8 9 9 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 21 22 20 96 95 69 125 122 87 121 119 87
+-144 139 99 177 172 135 197 193 154 210 208 158 214 212 158 214 212 158
+-210 208 158 204 201 155 194 191 148 194 189 146 204 201 155 214 212 158
+-239 239 170 251 251 187 251 251 187 251 251 187 251 251 187 214 212 158
+-188 184 146 145 141 105 53 55 47 12 12 12 15 15 15 63 64 60
+-63 64 60 41 42 42 31 33 31 23 24 24 17 18 17 12 15 15
+-11 13 13 9 11 11 8 9 9 7 9 9 6 8 8 6 8 8
+-6 7 7 6 7 7 6 8 8 6 8 8 6 8 8 6 8 8
+-6 8 8 7 9 9 7 9 9 7 9 9 7 9 9 7 9 9
+-7 9 9 7 9 9 7 9 9 7 9 9 7 9 9 8 8 7
+-43 45 43 251 251 187 156 151 111 8 10 10 7 9 9 7 9 9
+-21 22 21 51 52 50 55 56 53 55 57 54 58 59 55 58 59 55
+-75 75 61 158 153 112 197 193 154 224 223 159 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 214 212 158 204 201 155 194 189 146
+-190 186 136 197 193 154 210 208 158 224 223 159 251 251 187 251 251 187
+-251 251 187 251 251 187 239 239 170 210 208 158 197 193 154 176 171 126
+-125 122 87 36 38 35 14 14 13 14 14 13 15 15 15 15 15 15
+-15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15
+-15 15 15 14 14 13 13 13 13 12 12 12 10 10 9 3 4 4
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 7 7 5 71 71 57 131 127 93 158 153 112
+-177 172 135 197 193 154 214 212 158 239 239 170 251 251 187 251 251 187
+-238 237 168 210 208 158 204 201 155 197 193 154 204 201 155 214 212 158
+-251 251 187 251 251 187 251 251 187 251 251 187 251 251 187 214 212 158
+-197 193 154 156 151 111 66 65 55 12 12 12 37 39 37 58 59 55
+-58 59 55 41 42 42 31 33 31 22 24 23 17 17 17 12 14 14
+-10 12 12 8 10 10 6 8 8 6 8 8 6 7 7 6 7 7
+-6 7 7 5 7 7 6 7 7 6 7 7 6 8 8 6 8 8
+-6 8 8 6 8 8 6 8 8 7 9 9 7 9 9 7 9 9
+-7 9 9 6 8 8 6 8 8 6 8 8 6 8 8 6 8 8
+-61 63 57 197 193 154 16 19 19 6 8 8 6 8 8 8 9 9
+-41 42 42 47 48 46 51 52 50 51 52 50 55 56 53 55 56 53
+-71 71 57 158 153 112 197 193 154 224 223 159 251 251 187 251 251 187
+-251 251 187 251 251 187 239 239 170 214 212 158 204 201 155 194 189 146
+-190 186 136 197 193 154 210 208 158 239 239 170 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 224 223 159 204 201 155 177 172 135
+-121 119 87 30 31 28 13 13 13 14 14 13 14 14 13 14 14 13
+-14 14 13 14 14 13 15 15 15 15 15 15 14 14 13 13 13 13
+-12 12 12 12 12 12 10 10 9 4 5 5 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 48 49 45 131 127 93 174 170 121
+-194 189 146 210 208 158 239 239 170 251 251 187 251 251 187 251 251 187
+-251 251 187 214 212 158 204 201 155 197 193 154 204 201 155 210 208 158
+-239 239 170 251 251 187 251 251 187 251 251 187 239 239 170 214 212 158
+-194 191 148 156 151 111 71 71 57 19 20 19 51 52 50 51 52 50
+-51 52 50 41 42 42 30 32 31 21 22 21 17 17 17 13 13 13
+-9 11 11 8 9 9 6 8 8 6 7 7 6 7 7 5 7 7
+-5 6 5 5 6 5 5 7 7 5 7 7 6 7 7 6 7 7
+-6 8 8 6 8 8 6 8 8 6 7 7 6 7 7 6 7 7
+-6 7 7 6 8 8 6 8 8 6 8 8 6 8 8 6 8 8
+-55 56 53 43 45 43 6 8 8 6 8 8 6 8 8 47 48 46
+-60 60 56 47 48 46 46 47 45 47 48 46 38 39 37 10 12 12
+-66 65 55 145 141 105 197 193 154 214 212 158 251 251 187 251 251 187
+-251 251 187 251 251 187 224 223 159 210 208 158 194 191 148 184 181 136
+-184 181 136 194 189 146 204 201 155 224 223 159 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 239 239 170 210 208 158 181 176 137
+-115 113 82 21 22 20 13 13 13 13 13 13 13 13 13 13 13 13
+-14 14 13 13 13 13 13 13 13 13 13 13 12 12 12 11 11 11
+-10 10 9 6 7 7 1 1 1 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 2 2 1 66 65 55 144 139 99 178 174 128
+-204 201 155 214 212 158 251 251 187 251 251 187 251 251 187 251 251 187
+-251 251 187 214 212 158 204 201 155 194 191 148 197 193 154 204 201 155
+-214 212 158 239 239 170 239 239 170 239 239 170 214 212 158 210 208 158
+-184 181 136 149 145 103 66 65 55 41 42 42 47 48 46 46 47 45
+-43 45 43 39 40 39 28 31 30 21 22 21 16 16 16 10 12 12
+-8 10 10 6 8 8 6 7 7 6 7 7 5 6 5 5 6 5
+-5 6 5 5 6 5 5 6 5 5 6 5 5 7 7 5 7 7
+-6 7 7 6 7 7 6 7 7 5 7 7 5 7 7 5 7 7
+-5 7 7 6 7 7 6 7 7 6 7 7 6 7 7 6 8 8
+-6 8 8 6 8 8 6 7 7 6 7 7 46 47 45 156 151 111
+-105 104 92 58 59 55 43 45 43 32 34 33 6 8 8 6 8 8
+-49 51 48 125 122 87 181 176 137 204 201 155 214 212 158 239 239 170
+-239 239 170 214 212 158 210 208 158 197 193 154 181 176 137 176 171 126
+-176 171 126 184 181 136 197 193 154 210 208 158 239 239 170 251 251 187
+-251 251 187 251 251 187 251 251 187 251 251 187 210 208 158 177 172 135
+-99 98 80 13 13 13 12 12 12 12 12 12 13 13 13 12 12 12
+-12 12 12 12 12 12 11 11 11 11 11 11 8 9 9 4 5 5
+-1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 1 1 0 61 61 53 142 137 94 181 176 137
+-204 201 155 224 223 159 251 251 187 251 251 187 251 251 187 251 251 187
+-251 251 187 214 212 158 197 193 154 190 186 136 184 181 136 188 184 146
+-197 193 154 204 201 155 210 208 158 210 208 158 204 201 155 194 189 146
+-176 171 126 134 131 96 66 65 55 43 45 43 41 42 42 39 40 39
+-35 37 36 33 36 34 27 29 28 20 20 20 15 15 15 9 11 11
+-8 9 9 6 7 7 5 6 5 5 6 5 4 5 5 4 5 5
+-4 5 5 4 5 5 4 5 5 4 5 5 5 6 5 4 5 5
+-4 5 5 5 6 5 4 5 5 5 6 5 5 6 5 5 6 5
+-5 7 7 5 7 7 5 7 7 5 7 7 5 7 7 5 7 7
+-6 7 7 6 7 7 6 7 7 28 31 30 184 179 149 184 179 149
+-145 141 105 84 83 72 27 29 28 5 7 7 5 6 5 16 16 16
+-43 44 41 96 95 69 158 153 112 188 184 146 204 201 155 210 208 158
+-204 201 155 197 193 154 184 179 149 177 172 135 168 163 120 164 159 111
+-164 159 111 174 170 121 184 181 136 197 193 154 214 212 158 251 251 187
+-251 251 187 251 251 187 251 251 187 251 251 187 210 208 158 177 172 135
+-71 71 57 11 11 11 12 12 12 11 11 11 11 11 11 11 11 11
+-10 10 9 10 10 9 8 8 7 3 4 4 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 31 33 31 121 119 87 176 171 126
+-197 193 154 214 212 158 251 251 187 251 251 187 251 251 187 251 251 187
+-239 239 170 210 208 158 194 189 146 178 174 128 174 170 121 176 171 126
+-177 172 135 181 176 137 184 179 149 184 179 149 181 176 137 178 174 128
+-158 153 112 121 119 87 53 55 47 37 39 37 33 36 34 30 32 31
+-27 29 28 25 27 26 24 26 24 19 20 19 13 13 13 8 10 10
+-6 8 8 6 7 7 5 6 5 4 5 5 4 5 5 4 5 5
+-4 5 5 4 5 5 4 5 5 3 4 4 3 4 4 4 5 5
+-4 5 5 4 5 5 4 5 5 4 5 5 4 5 5 4 5 5
+-5 6 5 5 6 5 5 6 5 5 6 5 5 6 5 5 6 5
+-5 6 5 5 6 5 12 14 14 145 141 105 184 179 149 177 172 135
+-90 89 73 21 22 21 5 6 5 5 6 5 4 5 5 37 39 37
+-38 39 37 61 61 53 134 131 96 168 163 120 184 181 136 188 184 146
+-184 179 149 177 172 135 168 163 120 164 159 111 155 149 109 151 147 98
+-151 147 98 164 159 111 176 171 126 184 179 149 210 208 158 239 239 170
+-251 251 187 251 251 187 251 251 187 239 239 170 210 208 158 158 153 112
+-46 47 43 10 10 9 10 10 9 10 10 9 8 9 9 8 9 9
+-6 7 7 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 13 12 7 82 81 62 158 153 112
+-188 184 146 210 208 158 239 239 170 251 251 187 251 251 187 251 251 187
+-224 223 159 204 201 155 184 181 136 171 165 117 164 159 111 160 154 106
+-158 153 112 164 159 111 168 163 120 168 163 120 168 163 120 164 159 111
+-142 137 94 96 95 69 43 44 41 27 29 28 26 28 27 23 24 24
+-21 22 21 18 19 18 17 17 17 18 19 18 13 13 13 8 8 7
+-6 7 7 5 6 5 4 5 5 3 4 4 3 4 4 3 4 4
+-3 4 4 3 4 4 3 3 3 3 3 3 3 4 4 3 4 4
+-3 4 4 3 4 4 4 5 5 4 5 5 4 5 5 4 5 5
+-4 5 5 4 5 5 4 5 5 4 5 5 4 5 5 4 5 5
+-4 5 5 4 5 5 4 5 5 4 5 5 4 5 5 4 5 5
+-4 5 5 4 5 5 4 5 5 4 5 5 31 33 31 65 66 61
+-37 39 37 38 39 37 96 95 69 144 139 99 168 163 120 174 170 121
+-168 163 120 164 159 111 155 149 109 149 145 103 149 143 98 142 137 94
+-149 143 98 151 147 98 164 159 111 177 172 135 197 193 154 210 208 158
+-251 251 187 251 251 187 251 251 187 239 239 170 197 193 154 137 133 100
+-24 26 24 8 9 9 8 9 9 8 8 7 6 7 7 2 2 2
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 46 47 43 125 122 87
+-176 171 126 197 193 154 210 208 158 239 239 170 251 251 187 239 239 170
+-214 212 158 197 193 154 181 176 137 164 159 111 151 147 98 149 143 98
+-149 143 98 149 143 98 149 145 103 155 149 109 160 154 106 149 143 98
+-118 116 76 82 81 62 30 31 28 21 22 21 19 20 19 17 17 17
+-14 14 13 12 12 12 10 10 9 12 12 12 10 12 12 6 8 8
+-4 5 5 3 4 4 3 4 4 3 4 4 3 3 3 3 3 3
+-3 3 3 3 3 3 3 3 3 3 3 3 2 3 3 2 3 3
+-3 4 4 3 4 4 3 4 4 3 4 4 3 4 4 4 5 5
+-4 5 5 3 4 4 3 4 4 3 4 4 3 4 4 3 4 4
+-4 5 5 4 5 5 4 5 5 4 5 5 4 5 5 4 5 5
+-4 5 5 3 4 4 3 4 4 23 24 24 110 109 94 72 73 67
+-39 40 39 22 24 23 46 47 43 103 101 77 142 137 94 155 149 109
+-160 154 106 155 149 109 149 143 98 142 137 94 142 137 94 142 137 94
+-142 137 94 149 143 98 155 149 109 176 171 126 184 179 149 210 208 158
+-239 239 170 251 251 187 251 251 187 214 212 158 184 179 149 105 104 92
+-10 10 9 6 7 7 3 4 4 1 1 1 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 12 12 9 82 81 62
+-149 145 103 181 176 137 197 193 154 210 208 158 214 212 158 214 212 158
+-210 208 158 197 193 154 177 172 135 158 153 112 149 143 98 142 137 94
+-142 137 94 142 137 94 149 143 98 151 147 98 151 147 98 131 127 93
+-103 101 77 71 71 57 22 24 23 15 15 15 13 13 13 11 11 11
+-8 9 9 6 7 7 6 7 7 4 5 5 8 9 9 6 7 7
+-4 5 5 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2
+-2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3
+-2 3 3 2 3 3 2 3 3 3 4 4 3 4 4 3 4 4
+-3 4 4 3 4 4 3 3 3 3 4 4 3 4 4 3 4 4
+-3 4 4 3 4 4 3 4 4 3 4 4 3 4 4 3 4 4
+-3 4 4 3 4 4 21 22 21 145 141 105 145 141 105 72 73 67
+-17 18 17 3 4 4 21 22 20 66 65 55 118 116 76 142 137 94
+-149 143 98 151 147 98 149 143 98 142 137 94 142 137 94 142 137 94
+-142 137 94 149 143 98 155 149 109 168 163 120 184 179 149 210 208 158
+-239 239 170 251 251 187 251 251 187 210 208 158 177 172 135 71 71 57
+-3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 36 38 35
+-115 113 82 158 153 112 181 176 137 197 193 154 204 201 155 210 208 158
+-204 201 155 188 184 146 177 172 135 164 159 111 149 145 103 142 137 94
+-142 137 94 142 137 94 149 143 98 151 147 98 149 143 98 125 122 87
+-96 95 69 61 61 53 16 17 12 8 9 9 8 8 7 6 7 7
+-4 5 5 3 4 4 3 3 3 3 3 3 3 3 3 5 6 5
+-3 4 4 2 3 3 2 2 2 2 2 2 2 2 2 2 2 2
+-2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2
+-2 2 2 2 2 2 2 3 3 2 3 3 2 3 3 2 3 3
+-3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
+-3 3 3 2 3 3 2 3 3 3 4 4 3 4 4 3 4 4
+-3 4 4 3 4 4 3 4 4 8 9 9 8 8 7 3 3 3
+-3 3 3 3 3 3 9 9 8 36 38 35 82 81 62 118 116 76
+-142 137 94 151 147 98 151 147 98 151 147 98 149 143 98 149 143 98
+-149 143 98 151 147 98 160 154 106 176 171 126 188 184 146 210 208 158
+-239 239 170 251 251 187 239 239 170 210 208 158 156 151 111 31 33 31
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 7 5
+-66 65 55 125 122 87 158 153 112 181 176 137 194 189 146 197 193 154
+-197 193 154 184 179 149 177 172 135 168 163 120 156 151 111 151 147 98
+-151 147 98 151 147 98 151 147 98 161 156 96 149 143 98 118 116 76
+-82 81 62 53 55 47 12 12 9 4 5 5 3 4 4 3 3 3
+-3 3 3 3 3 3 2 2 2 2 2 2 1 1 1 1 2 2
+-3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
+-1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 2 2
+-1 2 2 1 2 2 1 2 2 2 2 2 2 2 2 2 3 3
+-2 3 3 2 3 3 2 3 3 2 3 3 2 2 2 2 2 2
+-2 3 3 2 3 3 2 3 3 2 3 3 2 3 3 2 3 3
+-2 3 3 2 3 3 2 3 3 2 3 3 2 3 3 3 3 3
+-3 3 3 3 3 3 72 73 67 61 61 53 53 55 47 96 95 69
+-131 127 93 151 147 98 161 156 96 161 156 96 151 147 98 151 147 98
+-161 156 96 160 154 106 164 159 111 177 172 135 197 193 154 210 208 158
+-239 239 170 251 251 187 224 223 159 197 193 154 131 127 93 9 9 8
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-24 26 24 82 81 62 131 127 93 164 159 111 178 174 128 188 184 146
+-188 184 146 188 184 146 181 176 137 176 171 126 168 163 120 164 159 111
+-160 154 106 160 154 106 160 154 106 160 154 106 151 147 98 125 122 87
+-82 81 62 61 61 53 12 12 9 3 3 3 3 3 3 2 2 2
+-2 2 2 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
+-0 0 0 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 2 2 1 2 2 1 2 2 1 2 2
+-1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
+-2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
+-2 3 3 2 3 3 2 3 3 2 3 3 2 3 3 2 3 3
+-2 3 3 30 32 31 72 73 67 31 33 31 36 38 35 82 81 62
+-118 116 76 149 143 98 161 156 96 161 156 96 161 156 96 160 154 106
+-165 161 109 165 161 109 176 171 126 188 184 146 204 201 155 214 212 158
+-239 239 170 239 239 170 214 212 158 184 179 149 82 81 62 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-2 2 2 43 44 41 96 95 69 131 127 93 160 154 106 176 171 126
+-184 181 136 184 181 136 184 181 136 181 176 137 178 174 128 174 170 121
+-171 165 117 173 167 111 173 167 111 173 167 111 160 154 106 131 127 93
+-96 95 69 66 65 55 16 17 12 2 2 2 1 1 1 1 1 1
+-1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 2 2 1 2 2 1 2 2 1 2 2 1 2 2 2 2 2
+-2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
+-2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
+-2 2 2 2 2 2 2 2 2 10 9 6 30 31 28 71 71 57
+-118 116 76 149 143 98 165 161 109 165 161 109 165 161 109 173 167 111
+-173 167 111 176 171 126 184 181 136 197 193 154 210 208 158 224 223 159
+-251 251 187 239 239 170 210 208 158 168 163 120 40 41 39 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 13 12 7 61 61 53 96 95 69 131 127 93 160 154 106
+-176 171 126 184 181 136 184 181 136 188 184 146 184 181 136 184 181 136
+-184 181 136 186 182 128 186 182 128 178 174 128 174 170 121 149 145 103
+-118 116 76 82 81 62 21 22 20 1 1 1 1 1 1 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2
+-1 2 2 1 2 2 1 2 2 1 2 2 1 2 2 2 2 2
+-2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
+-2 2 2 2 2 2 2 2 2 3 3 3 30 31 28 66 65 55
+-118 116 76 149 143 98 165 161 109 173 167 111 173 167 111 174 170 121
+-186 182 128 190 186 136 197 193 154 210 208 158 224 223 159 251 251 187
+-251 251 187 239 239 170 197 193 154 137 133 100 12 12 9 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 30 31 28 71 71 57 103 101 77 134 131 96
+-164 159 111 176 171 126 184 181 136 188 184 146 194 189 146 197 193 154
+-197 193 154 197 193 154 194 191 148 194 189 146 190 186 136 176 171 126
+-145 141 105 103 101 77 40 41 39 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 2 2
+-1 2 2 1 2 2 1 2 2 1 2 2 1 2 2 1 2 2
+-1 2 2 1 2 2 1 2 2 1 2 2 30 31 28 71 71 57
+-118 116 76 160 154 106 173 167 111 178 174 128 186 182 128 190 186 136
+-194 191 148 204 201 155 210 208 158 224 223 159 251 251 187 251 251 187
+-251 251 187 214 212 158 184 179 149 84 83 72 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 5 5 3 43 44 41 82 81 62 103 101 77
+-142 137 94 165 161 109 178 174 128 190 186 136 197 193 154 204 201 155
+-210 208 158 210 208 158 210 208 158 210 208 158 210 208 158 197 193 154
+-177 172 135 145 141 105 79 78 62 5 4 3 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 2 2 1 2 2 30 31 28 82 81 62
+-142 137 94 165 161 109 178 174 128 190 186 136 194 191 148 204 201 155
+-210 208 158 214 212 158 239 239 170 251 251 187 251 251 187 251 251 187
+-251 251 187 210 208 158 168 163 120 36 38 35 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 16 17 12 53 55 47 82 81 62
+-118 116 76 151 147 98 171 165 117 184 181 136 194 191 148 210 208 158
+-214 212 158 224 223 159 239 239 170 239 239 170 224 223 159 214 212 158
+-197 193 154 176 171 126 115 113 82 24 26 24 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 40 41 39 103 101 77
+-151 147 98 176 171 126 190 186 136 197 193 154 210 208 158 214 212 158
+-239 239 170 251 251 187 251 251 187 251 251 187 251 251 187 251 251 187
+-239 239 170 197 193 154 110 109 94 3 4 3 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 30 31 28 66 65 55
+-96 95 69 125 122 87 160 154 106 178 174 128 194 189 146 204 201 155
+-214 212 158 239 239 170 251 251 187 251 251 187 251 251 187 239 239 170
+-210 208 158 188 184 146 149 145 103 61 61 53 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 61 61 53 131 127 93
+-164 159 111 184 181 136 197 193 154 210 208 158 224 223 159 251 251 187
+-251 251 187 251 251 187 251 251 187 251 251 187 251 251 187 251 251 187
+-210 208 158 168 163 120 43 44 41 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 4 3 2 36 38 35
+-71 71 57 96 95 69 142 137 94 165 161 109 184 181 136 197 193 154
+-210 208 158 239 239 170 251 251 187 251 251 187 251 251 187 251 251 187
+-214 212 158 197 193 154 168 163 120 103 101 77 7 7 5 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-1 1 1 0 0 0 0 0 0 0 0 0 82 81 62 142 137 94
+-174 170 121 194 189 146 210 208 158 224 223 159 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 251 251 187 251 251 187 224 223 159
+-184 179 149 99 98 80 3 3 3 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 7 5
+-43 44 41 82 81 62 118 116 76 142 137 94 171 165 117 190 186 136
+-204 201 155 224 223 159 251 251 187 251 251 187 251 251 187 251 251 187
+-214 212 158 197 193 154 174 170 121 125 122 87 30 31 28 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
+-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 3 4 3 82 81 62 149 143 98
+-176 171 126 194 191 148 210 208 158 239 239 170 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 251 251 187 239 239 170 204 201 155
+-145 141 105 30 31 28 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-10 9 6 46 47 43 82 81 62 118 116 76 149 143 98 174 170 121
+-194 189 146 210 208 158 224 223 159 251 251 187 251 251 187 224 223 159
+-210 208 158 194 191 148 174 170 121 134 131 96 53 55 47 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 7 7 5 96 95 69 149 143 98
+-176 171 126 194 191 148 210 208 158 239 239 170 251 251 187 251 251 187
+-251 251 187 251 251 187 251 251 187 239 239 170 210 208 158 177 172 135
+-75 75 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 10 9 6 46 47 43 82 81 62 118 116 76 149 143 98
+-176 171 126 194 191 148 210 208 158 214 212 158 214 212 158 210 208 158
+-197 193 154 184 181 136 164 159 111 131 127 93 53 55 47 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 7 7 5 96 95 69 149 143 98
+-174 170 121 194 189 146 204 201 155 214 212 158 239 239 170 251 251 187
+-251 251 187 251 251 187 239 239 170 210 208 158 184 179 149 110 109 94
+-12 12 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 10 9 6 43 44 41 82 81 62 115 113 82
+-144 139 99 168 163 120 188 184 146 197 193 154 197 193 154 194 189 146
+-184 181 136 174 170 121 151 147 98 118 116 76 36 38 35 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 4 3 2 82 81 62 142 137 94
+-171 165 117 186 182 128 194 191 148 210 208 158 214 212 158 224 223 159
+-239 239 170 224 223 159 210 208 158 184 179 149 137 133 100 36 38 35
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 7 7 5 36 38 35 71 71 57
+-103 101 77 131 127 93 155 149 109 168 163 120 168 163 120 168 163 120
+-164 159 111 149 143 98 125 122 87 82 81 62 13 12 7 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 61 61 53 125 122 87
+-160 154 106 174 170 121 184 181 136 194 189 146 204 201 155 210 208 158
+-210 208 158 204 201 155 184 179 149 145 141 105 61 61 53 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 3 3 2 30 31 28
+-61 61 53 82 81 62 103 101 77 121 119 87 125 122 87 125 122 87
+-118 116 76 103 101 77 79 78 62 24 26 24 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 25 27 25 96 95 69
+-142 137 94 160 154 106 171 165 117 178 174 128 184 181 136 184 181 136
+-181 176 137 177 172 135 145 141 105 75 75 61 5 5 3 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-16 17 12 40 41 39 61 61 53 71 71 57 71 71 57 71 71 57
+-66 65 55 43 44 41 12 12 9 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 46 47 43
+-96 95 69 125 122 87 142 137 94 149 145 103 155 149 109 155 149 109
+-145 141 105 121 119 87 66 65 55 7 7 5 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 1 1 1 16 17 12 24 26 24 25 27 25 19 20 18
+-7 7 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1
+-25 27 25 61 61 53 82 81 62 96 95 69 96 95 69 82 81 62
+-61 61 53 25 27 25 2 2 1 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 5 6 5 13 12 7 10 9 6 3 4 3
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+-0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 6 6 6 6 6 6 10 10 10 10 10 10
++ 10 10 10 6 6 6 6 6 6 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 6 6 6 10 10 10 14 14 14
++ 22 22 22 26 26 26 30 30 30 34 34 34
++ 30 30 30 30 30 30 26 26 26 18 18 18
++ 14 14 14 10 10 10 6 6 6 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 1 0 0 1 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 6 6 6 14 14 14 26 26 26 42 42 42
++ 54 54 54 66 66 66 78 78 78 78 78 78
++ 78 78 78 74 74 74 66 66 66 54 54 54
++ 42 42 42 26 26 26 18 18 18 10 10 10
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 1 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 22 22 22 42 42 42 66 66 66 86 86 86
++ 66 66 66 38 38 38 38 38 38 22 22 22
++ 26 26 26 34 34 34 54 54 54 66 66 66
++ 86 86 86 70 70 70 46 46 46 26 26 26
++ 14 14 14 6 6 6 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 1 0 0 1 0 0 1 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 10 10 10 26 26 26
++ 50 50 50 82 82 82 58 58 58 6 6 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 6 6 6 54 54 54 86 86 86 66 66 66
++ 38 38 38 18 18 18 6 6 6 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 6 6 6 22 22 22 50 50 50
++ 78 78 78 34 34 34 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 6 6 6 70 70 70
++ 78 78 78 46 46 46 22 22 22 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 1 0 0 1 0 0 1 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 6 6 6 18 18 18 42 42 42 82 82 82
++ 26 26 26 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 14 14 14
++ 46 46 46 34 34 34 6 6 6 2 2 6
++ 42 42 42 78 78 78 42 42 42 18 18 18
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 1 0 0 0 0 0 1 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 10 10 10 30 30 30 66 66 66 58 58 58
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 26 26 26
++ 86 86 86 101 101 101 46 46 46 10 10 10
++ 2 2 6 58 58 58 70 70 70 34 34 34
++ 10 10 10 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 1 0 0 1 0 0 1 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 14 14 14 42 42 42 86 86 86 10 10 10
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 30 30 30
++ 94 94 94 94 94 94 58 58 58 26 26 26
++ 2 2 6 6 6 6 78 78 78 54 54 54
++ 22 22 22 6 6 6 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 22 22 22 62 62 62 62 62 62 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 26 26 26
++ 54 54 54 38 38 38 18 18 18 10 10 10
++ 2 2 6 2 2 6 34 34 34 82 82 82
++ 38 38 38 14 14 14 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 1 0 0 1 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 30 30 30 78 78 78 30 30 30 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 10 10 10
++ 10 10 10 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 78 78 78
++ 50 50 50 18 18 18 6 6 6 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 1 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 38 38 38 86 86 86 14 14 14 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 54 54 54
++ 66 66 66 26 26 26 6 6 6 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 1 0 0 1 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 14 14 14
++ 42 42 42 82 82 82 2 2 6 2 2 6
++ 2 2 6 6 6 6 10 10 10 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 6 6 6
++ 14 14 14 10 10 10 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 18 18 18
++ 82 82 82 34 34 34 10 10 10 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 1 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 14 14 14
++ 46 46 46 86 86 86 2 2 6 2 2 6
++ 6 6 6 6 6 6 22 22 22 34 34 34
++ 6 6 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 18 18 18 34 34 34
++ 10 10 10 50 50 50 22 22 22 2 2 6
++ 2 2 6 2 2 6 2 2 6 10 10 10
++ 86 86 86 42 42 42 14 14 14 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 1 0 0 1 0 0 1 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 14 14 14
++ 46 46 46 86 86 86 2 2 6 2 2 6
++ 38 38 38 116 116 116 94 94 94 22 22 22
++ 22 22 22 2 2 6 2 2 6 2 2 6
++ 14 14 14 86 86 86 138 138 138 162 162 162
++154 154 154 38 38 38 26 26 26 6 6 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 86 86 86 46 46 46 14 14 14 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 14 14 14
++ 46 46 46 86 86 86 2 2 6 14 14 14
++134 134 134 198 198 198 195 195 195 116 116 116
++ 10 10 10 2 2 6 2 2 6 6 6 6
++101 98 89 187 187 187 210 210 210 218 218 218
++214 214 214 134 134 134 14 14 14 6 6 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 86 86 86 50 50 50 18 18 18 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 1 0 0 0
++ 0 0 1 0 0 1 0 0 1 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 14 14 14
++ 46 46 46 86 86 86 2 2 6 54 54 54
++218 218 218 195 195 195 226 226 226 246 246 246
++ 58 58 58 2 2 6 2 2 6 30 30 30
++210 210 210 253 253 253 174 174 174 123 123 123
++221 221 221 234 234 234 74 74 74 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 70 70 70 58 58 58 22 22 22 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 14 14 14
++ 46 46 46 82 82 82 2 2 6 106 106 106
++170 170 170 26 26 26 86 86 86 226 226 226
++123 123 123 10 10 10 14 14 14 46 46 46
++231 231 231 190 190 190 6 6 6 70 70 70
++ 90 90 90 238 238 238 158 158 158 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 70 70 70 58 58 58 22 22 22 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 1 0 0 0
++ 0 0 1 0 0 1 0 0 1 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 14 14 14
++ 42 42 42 86 86 86 6 6 6 116 116 116
++106 106 106 6 6 6 70 70 70 149 149 149
++128 128 128 18 18 18 38 38 38 54 54 54
++221 221 221 106 106 106 2 2 6 14 14 14
++ 46 46 46 190 190 190 198 198 198 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 74 74 74 62 62 62 22 22 22 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 1 0 0 0
++ 0 0 1 0 0 0 0 0 1 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 14 14 14
++ 42 42 42 94 94 94 14 14 14 101 101 101
++128 128 128 2 2 6 18 18 18 116 116 116
++118 98 46 121 92 8 121 92 8 98 78 10
++162 162 162 106 106 106 2 2 6 2 2 6
++ 2 2 6 195 195 195 195 195 195 6 6 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 74 74 74 62 62 62 22 22 22 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 1 0 0 1
++ 0 0 1 0 0 0 0 0 1 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 38 38 38 90 90 90 14 14 14 58 58 58
++210 210 210 26 26 26 54 38 6 154 114 10
++226 170 11 236 186 11 225 175 15 184 144 12
++215 174 15 175 146 61 37 26 9 2 2 6
++ 70 70 70 246 246 246 138 138 138 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 70 70 70 66 66 66 26 26 26 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 38 38 38 86 86 86 14 14 14 10 10 10
++195 195 195 188 164 115 192 133 9 225 175 15
++239 182 13 234 190 10 232 195 16 232 200 30
++245 207 45 241 208 19 232 195 16 184 144 12
++218 194 134 211 206 186 42 42 42 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 50 50 50 74 74 74 30 30 30 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 34 34 34 86 86 86 14 14 14 2 2 6
++121 87 25 192 133 9 219 162 10 239 182 13
++236 186 11 232 195 16 241 208 19 244 214 54
++246 218 60 246 218 38 246 215 20 241 208 19
++241 208 19 226 184 13 121 87 25 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 50 50 50 82 82 82 34 34 34 10 10 10
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 34 34 34 82 82 82 30 30 30 61 42 6
++180 123 7 206 145 10 230 174 11 239 182 13
++234 190 10 238 202 15 241 208 19 246 218 74
++246 218 38 246 215 20 246 215 20 246 215 20
++226 184 13 215 174 15 184 144 12 6 6 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 26 26 26 94 94 94 42 42 42 14 14 14
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 30 30 30 78 78 78 50 50 50 104 69 6
++192 133 9 216 158 10 236 178 12 236 186 11
++232 195 16 241 208 19 244 214 54 245 215 43
++246 215 20 246 215 20 241 208 19 198 155 10
++200 144 11 216 158 10 156 118 10 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 6 6 6 90 90 90 54 54 54 18 18 18
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 30 30 30 78 78 78 46 46 46 22 22 22
++137 92 6 210 162 10 239 182 13 238 190 10
++238 202 15 241 208 19 246 215 20 246 215 20
++241 208 19 203 166 17 185 133 11 210 150 10
++216 158 10 210 150 10 102 78 10 2 2 6
++ 6 6 6 54 54 54 14 14 14 2 2 6
++ 2 2 6 62 62 62 74 74 74 30 30 30
++ 10 10 10 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 34 34 34 78 78 78 50 50 50 6 6 6
++ 94 70 30 139 102 15 190 146 13 226 184 13
++232 200 30 232 195 16 215 174 15 190 146 13
++168 122 10 192 133 9 210 150 10 213 154 11
++202 150 34 182 157 106 101 98 89 2 2 6
++ 2 2 6 78 78 78 116 116 116 58 58 58
++ 2 2 6 22 22 22 90 90 90 46 46 46
++ 18 18 18 6 6 6 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 38 38 38 86 86 86 50 50 50 6 6 6
++128 128 128 174 154 114 156 107 11 168 122 10
++198 155 10 184 144 12 197 138 11 200 144 11
++206 145 10 206 145 10 197 138 11 188 164 115
++195 195 195 198 198 198 174 174 174 14 14 14
++ 2 2 6 22 22 22 116 116 116 116 116 116
++ 22 22 22 2 2 6 74 74 74 70 70 70
++ 30 30 30 10 10 10 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 6 6 6 18 18 18
++ 50 50 50 101 101 101 26 26 26 10 10 10
++138 138 138 190 190 190 174 154 114 156 107 11
++197 138 11 200 144 11 197 138 11 192 133 9
++180 123 7 190 142 34 190 178 144 187 187 187
++202 202 202 221 221 221 214 214 214 66 66 66
++ 2 2 6 2 2 6 50 50 50 62 62 62
++ 6 6 6 2 2 6 10 10 10 90 90 90
++ 50 50 50 18 18 18 6 6 6 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 10 10 10 34 34 34
++ 74 74 74 74 74 74 2 2 6 6 6 6
++144 144 144 198 198 198 190 190 190 178 166 146
++154 121 60 156 107 11 156 107 11 168 124 44
++174 154 114 187 187 187 190 190 190 210 210 210
++246 246 246 253 253 253 253 253 253 182 182 182
++ 6 6 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 62 62 62
++ 74 74 74 34 34 34 14 14 14 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 10 10 10 22 22 22 54 54 54
++ 94 94 94 18 18 18 2 2 6 46 46 46
++234 234 234 221 221 221 190 190 190 190 190 190
++190 190 190 187 187 187 187 187 187 190 190 190
++190 190 190 195 195 195 214 214 214 242 242 242
++253 253 253 253 253 253 253 253 253 253 253 253
++ 82 82 82 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 14 14 14
++ 86 86 86 54 54 54 22 22 22 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 6 6 6 18 18 18 46 46 46 90 90 90
++ 46 46 46 18 18 18 6 6 6 182 182 182
++253 253 253 246 246 246 206 206 206 190 190 190
++190 190 190 190 190 190 190 190 190 190 190 190
++206 206 206 231 231 231 250 250 250 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++202 202 202 14 14 14 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 42 42 42 86 86 86 42 42 42 18 18 18
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 14 14 14 38 38 38 74 74 74 66 66 66
++ 2 2 6 6 6 6 90 90 90 250 250 250
++253 253 253 253 253 253 238 238 238 198 198 198
++190 190 190 190 190 190 195 195 195 221 221 221
++246 246 246 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 82 82 82 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 78 78 78 70 70 70 34 34 34
++ 14 14 14 6 6 6 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 14 14 14
++ 34 34 34 66 66 66 78 78 78 6 6 6
++ 2 2 6 18 18 18 218 218 218 253 253 253
++253 253 253 253 253 253 253 253 253 246 246 246
++226 226 226 231 231 231 246 246 246 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 178 178 178 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 18 18 18 90 90 90 62 62 62
++ 30 30 30 10 10 10 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 10 10 10 26 26 26
++ 58 58 58 90 90 90 18 18 18 2 2 6
++ 2 2 6 110 110 110 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++250 250 250 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 231 231 231 18 18 18 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 18 18 18 94 94 94
++ 54 54 54 26 26 26 10 10 10 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 6 6 6 22 22 22 50 50 50
++ 90 90 90 26 26 26 2 2 6 2 2 6
++ 14 14 14 195 195 195 250 250 250 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++250 250 250 242 242 242 54 54 54 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 38 38 38
++ 86 86 86 50 50 50 22 22 22 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 6 6 6 14 14 14 38 38 38 82 82 82
++ 34 34 34 2 2 6 2 2 6 2 2 6
++ 42 42 42 195 195 195 246 246 246 253 253 253
++253 253 253 253 253 253 253 253 253 250 250 250
++242 242 242 242 242 242 250 250 250 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 250 250 250 246 246 246 238 238 238
++226 226 226 231 231 231 101 101 101 6 6 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 38 38 38 82 82 82 42 42 42 14 14 14
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 10 10 10 26 26 26 62 62 62 66 66 66
++ 2 2 6 2 2 6 2 2 6 6 6 6
++ 70 70 70 170 170 170 206 206 206 234 234 234
++246 246 246 250 250 250 250 250 250 238 238 238
++226 226 226 231 231 231 238 238 238 250 250 250
++250 250 250 250 250 250 246 246 246 231 231 231
++214 214 214 206 206 206 202 202 202 202 202 202
++198 198 198 202 202 202 182 182 182 18 18 18
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 62 62 62 66 66 66 30 30 30
++ 10 10 10 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 14 14 14 42 42 42 82 82 82 18 18 18
++ 2 2 6 2 2 6 2 2 6 10 10 10
++ 94 94 94 182 182 182 218 218 218 242 242 242
++250 250 250 253 253 253 253 253 253 250 250 250
++234 234 234 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 246 246 246
++238 238 238 226 226 226 210 210 210 202 202 202
++195 195 195 195 195 195 210 210 210 158 158 158
++ 6 6 6 14 14 14 50 50 50 14 14 14
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 6 6 6 86 86 86 46 46 46
++ 18 18 18 6 6 6 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 22 22 22 54 54 54 70 70 70 2 2 6
++ 2 2 6 10 10 10 2 2 6 22 22 22
++166 166 166 231 231 231 250 250 250 253 253 253
++253 253 253 253 253 253 253 253 253 250 250 250
++242 242 242 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 246 246 246
++231 231 231 206 206 206 198 198 198 226 226 226
++ 94 94 94 2 2 6 6 6 6 38 38 38
++ 30 30 30 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 62 62 62 66 66 66
++ 26 26 26 10 10 10 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 30 30 30 74 74 74 50 50 50 2 2 6
++ 26 26 26 26 26 26 2 2 6 106 106 106
++238 238 238 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 246 246 246 218 218 218 202 202 202
++210 210 210 14 14 14 2 2 6 2 2 6
++ 30 30 30 22 22 22 2 2 6 2 2 6
++ 2 2 6 2 2 6 18 18 18 86 86 86
++ 42 42 42 14 14 14 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 14 14 14
++ 42 42 42 90 90 90 22 22 22 2 2 6
++ 42 42 42 2 2 6 18 18 18 218 218 218
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 250 250 250 221 221 221
++218 218 218 101 101 101 2 2 6 14 14 14
++ 18 18 18 38 38 38 10 10 10 2 2 6
++ 2 2 6 2 2 6 2 2 6 78 78 78
++ 58 58 58 22 22 22 6 6 6 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 6 6 6 18 18 18
++ 54 54 54 82 82 82 2 2 6 26 26 26
++ 22 22 22 2 2 6 123 123 123 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 250 250 250
++238 238 238 198 198 198 6 6 6 38 38 38
++ 58 58 58 26 26 26 38 38 38 2 2 6
++ 2 2 6 2 2 6 2 2 6 46 46 46
++ 78 78 78 30 30 30 10 10 10 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 10 10 10 30 30 30
++ 74 74 74 58 58 58 2 2 6 42 42 42
++ 2 2 6 22 22 22 231 231 231 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 250 250 250
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 246 246 246 46 46 46 38 38 38
++ 42 42 42 14 14 14 38 38 38 14 14 14
++ 2 2 6 2 2 6 2 2 6 6 6 6
++ 86 86 86 46 46 46 14 14 14 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 6 6 6 14 14 14 42 42 42
++ 90 90 90 18 18 18 18 18 18 26 26 26
++ 2 2 6 116 116 116 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 250 250 250 238 238 238
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 94 94 94 6 6 6
++ 2 2 6 2 2 6 10 10 10 34 34 34
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 74 74 74 58 58 58 22 22 22 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 10 10 10 26 26 26 66 66 66
++ 82 82 82 2 2 6 38 38 38 6 6 6
++ 14 14 14 210 210 210 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 246 246 246 242 242 242
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 144 144 144 2 2 6
++ 2 2 6 2 2 6 2 2 6 46 46 46
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 42 42 42 74 74 74 30 30 30 10 10 10
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 6 6 6 14 14 14 42 42 42 90 90 90
++ 26 26 26 6 6 6 42 42 42 2 2 6
++ 74 74 74 250 250 250 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 242 242 242 242 242 242
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 182 182 182 2 2 6
++ 2 2 6 2 2 6 2 2 6 46 46 46
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 10 10 10 86 86 86 38 38 38 10 10 10
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 10 10 10 26 26 26 66 66 66 82 82 82
++ 2 2 6 22 22 22 18 18 18 2 2 6
++149 149 149 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 234 234 234 242 242 242
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 206 206 206 2 2 6
++ 2 2 6 2 2 6 2 2 6 38 38 38
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 6 6 6 86 86 86 46 46 46 14 14 14
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 18 18 18 46 46 46 86 86 86 18 18 18
++ 2 2 6 34 34 34 10 10 10 6 6 6
++210 210 210 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 234 234 234 242 242 242
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 221 221 221 6 6 6
++ 2 2 6 2 2 6 6 6 6 30 30 30
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 82 82 82 54 54 54 18 18 18
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 26 26 26 66 66 66 62 62 62 2 2 6
++ 2 2 6 38 38 38 10 10 10 26 26 26
++238 238 238 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 231 231 231 238 238 238
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 231 231 231 6 6 6
++ 2 2 6 2 2 6 10 10 10 30 30 30
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 66 66 66 58 58 58 22 22 22
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 38 38 38 78 78 78 6 6 6 2 2 6
++ 2 2 6 46 46 46 14 14 14 42 42 42
++246 246 246 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 231 231 231 242 242 242
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 234 234 234 10 10 10
++ 2 2 6 2 2 6 22 22 22 14 14 14
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 66 66 66 62 62 62 22 22 22
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 6 6 6 18 18 18
++ 50 50 50 74 74 74 2 2 6 2 2 6
++ 14 14 14 70 70 70 34 34 34 62 62 62
++250 250 250 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 231 231 231 246 246 246
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 234 234 234 14 14 14
++ 2 2 6 2 2 6 30 30 30 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 66 66 66 62 62 62 22 22 22
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 6 6 6 18 18 18
++ 54 54 54 62 62 62 2 2 6 2 2 6
++ 2 2 6 30 30 30 46 46 46 70 70 70
++250 250 250 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 231 231 231 246 246 246
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 226 226 226 10 10 10
++ 2 2 6 6 6 6 30 30 30 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 66 66 66 58 58 58 22 22 22
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 6 6 6 22 22 22
++ 58 58 58 62 62 62 2 2 6 2 2 6
++ 2 2 6 2 2 6 30 30 30 78 78 78
++250 250 250 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 231 231 231 246 246 246
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 206 206 206 2 2 6
++ 22 22 22 34 34 34 18 14 6 22 22 22
++ 26 26 26 18 18 18 6 6 6 2 2 6
++ 2 2 6 82 82 82 54 54 54 18 18 18
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 6 6 6 26 26 26
++ 62 62 62 106 106 106 74 54 14 185 133 11
++210 162 10 121 92 8 6 6 6 62 62 62
++238 238 238 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 231 231 231 246 246 246
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 158 158 158 18 18 18
++ 14 14 14 2 2 6 2 2 6 2 2 6
++ 6 6 6 18 18 18 66 66 66 38 38 38
++ 6 6 6 94 94 94 50 50 50 18 18 18
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 10 10 10 10 10 10 18 18 18 38 38 38
++ 78 78 78 142 134 106 216 158 10 242 186 14
++246 190 14 246 190 14 156 118 10 10 10 10
++ 90 90 90 238 238 238 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 231 231 231 250 250 250
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 246 230 190
++238 204 91 238 204 91 181 142 44 37 26 9
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 38 38 38 46 46 46
++ 26 26 26 106 106 106 54 54 54 18 18 18
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 6 6 6 14 14 14 22 22 22
++ 30 30 30 38 38 38 50 50 50 70 70 70
++106 106 106 190 142 34 226 170 11 242 186 14
++246 190 14 246 190 14 246 190 14 154 114 10
++ 6 6 6 74 74 74 226 226 226 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 231 231 231 250 250 250
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 228 184 62
++241 196 14 241 208 19 232 195 16 38 30 10
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 6 6 6 30 30 30 26 26 26
++203 166 17 154 142 90 66 66 66 26 26 26
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 6 6 6 18 18 18 38 38 38 58 58 58
++ 78 78 78 86 86 86 101 101 101 123 123 123
++175 146 61 210 150 10 234 174 13 246 186 14
++246 190 14 246 190 14 246 190 14 238 190 10
++102 78 10 2 2 6 46 46 46 198 198 198
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 234 234 234 242 242 242
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 224 178 62
++242 186 14 241 196 14 210 166 10 22 18 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 6 6 6 121 92 8
++238 202 15 232 195 16 82 82 82 34 34 34
++ 10 10 10 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 14 14 14 38 38 38 70 70 70 154 122 46
++190 142 34 200 144 11 197 138 11 197 138 11
++213 154 11 226 170 11 242 186 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++225 175 15 46 32 6 2 2 6 22 22 22
++158 158 158 250 250 250 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 250 250 250 242 242 242 224 178 62
++239 182 13 236 186 11 213 154 11 46 32 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 61 42 6 225 175 15
++238 190 10 236 186 11 112 100 78 42 42 42
++ 14 14 14 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 22 22 22 54 54 54 154 122 46 213 154 11
++226 170 11 230 174 11 226 170 11 226 170 11
++236 178 12 242 186 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++241 196 14 184 144 12 10 10 10 2 2 6
++ 6 6 6 116 116 116 242 242 242 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 231 231 231 198 198 198 214 170 54
++236 178 12 236 178 12 210 150 10 137 92 6
++ 18 14 6 2 2 6 2 2 6 2 2 6
++ 6 6 6 70 47 6 200 144 11 236 178 12
++239 182 13 239 182 13 124 112 88 58 58 58
++ 22 22 22 6 6 6 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 30 30 30 70 70 70 180 133 36 226 170 11
++239 182 13 242 186 14 242 186 14 246 186 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 232 195 16 98 70 6 2 2 6
++ 2 2 6 2 2 6 66 66 66 221 221 221
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 206 206 206 198 198 198 214 166 58
++230 174 11 230 174 11 216 158 10 192 133 9
++163 110 8 116 81 8 102 78 10 116 81 8
++167 114 7 197 138 11 226 170 11 239 182 13
++242 186 14 242 186 14 162 146 94 78 78 78
++ 34 34 34 14 14 14 6 6 6 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 30 30 30 78 78 78 190 142 34 226 170 11
++239 182 13 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 241 196 14 203 166 17 22 18 6
++ 2 2 6 2 2 6 2 2 6 38 38 38
++218 218 218 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++250 250 250 206 206 206 198 198 198 202 162 69
++226 170 11 236 178 12 224 166 10 210 150 10
++200 144 11 197 138 11 192 133 9 197 138 11
++210 150 10 226 170 11 242 186 14 246 190 14
++246 190 14 246 186 14 225 175 15 124 112 88
++ 62 62 62 30 30 30 14 14 14 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 30 30 30 78 78 78 174 135 50 224 166 10
++239 182 13 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 241 196 14 139 102 15
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 78 78 78 250 250 250 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++250 250 250 214 214 214 198 198 198 190 150 46
++219 162 10 236 178 12 234 174 13 224 166 10
++216 158 10 213 154 11 213 154 11 216 158 10
++226 170 11 239 182 13 246 190 14 246 190 14
++246 190 14 246 190 14 242 186 14 206 162 42
++101 101 101 58 58 58 30 30 30 14 14 14
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 30 30 30 74 74 74 174 135 50 216 158 10
++236 178 12 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 241 196 14 226 184 13
++ 61 42 6 2 2 6 2 2 6 2 2 6
++ 22 22 22 238 238 238 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 226 226 226 187 187 187 180 133 36
++216 158 10 236 178 12 239 182 13 236 178 12
++230 174 11 226 170 11 226 170 11 230 174 11
++236 178 12 242 186 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 186 14 239 182 13
++206 162 42 106 106 106 66 66 66 34 34 34
++ 14 14 14 6 6 6 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 26 26 26 70 70 70 163 133 67 213 154 11
++236 178 12 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 241 196 14
++190 146 13 18 14 6 2 2 6 2 2 6
++ 46 46 46 246 246 246 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 221 221 221 86 86 86 156 107 11
++216 158 10 236 178 12 242 186 14 246 186 14
++242 186 14 239 182 13 239 182 13 242 186 14
++242 186 14 246 186 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++242 186 14 225 175 15 142 122 72 66 66 66
++ 30 30 30 10 10 10 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 26 26 26 70 70 70 163 133 67 210 150 10
++236 178 12 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++232 195 16 121 92 8 34 34 34 106 106 106
++221 221 221 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++242 242 242 82 82 82 18 14 6 163 110 8
++216 158 10 236 178 12 242 186 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 242 186 14 163 133 67
++ 46 46 46 18 18 18 6 6 6 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 10 10 10
++ 30 30 30 78 78 78 163 133 67 210 150 10
++236 178 12 246 186 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++241 196 14 215 174 15 190 178 144 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 218 218 218
++ 58 58 58 2 2 6 22 18 6 167 114 7
++216 158 10 236 178 12 246 186 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 186 14 242 186 14 190 150 46
++ 54 54 54 22 22 22 6 6 6 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 14 14 14
++ 38 38 38 86 86 86 180 133 36 213 154 11
++236 178 12 246 186 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 232 195 16 190 146 13 214 214 214
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 250 250 250 170 170 170 26 26 26
++ 2 2 6 2 2 6 37 26 9 163 110 8
++219 162 10 239 182 13 246 186 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 186 14 236 178 12 224 166 10 142 122 72
++ 46 46 46 18 18 18 6 6 6 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 6 6 6 18 18 18
++ 50 50 50 109 106 95 192 133 9 224 166 10
++242 186 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++242 186 14 226 184 13 210 162 10 142 110 46
++226 226 226 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++253 253 253 253 253 253 253 253 253 253 253 253
++198 198 198 66 66 66 2 2 6 2 2 6
++ 2 2 6 2 2 6 50 34 6 156 107 11
++219 162 10 239 182 13 246 186 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 242 186 14
++234 174 13 213 154 11 154 122 46 66 66 66
++ 30 30 30 10 10 10 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 6 6 6 22 22 22
++ 58 58 58 154 121 60 206 145 10 234 174 13
++242 186 14 246 186 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 186 14 236 178 12 210 162 10 163 110 8
++ 61 42 6 138 138 138 218 218 218 250 250 250
++253 253 253 253 253 253 253 253 253 250 250 250
++242 242 242 210 210 210 144 144 144 66 66 66
++ 6 6 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 61 42 6 163 110 8
++216 158 10 236 178 12 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 239 182 13 230 174 11 216 158 10
++190 142 34 124 112 88 70 70 70 38 38 38
++ 18 18 18 6 6 6 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 6 6 6 22 22 22
++ 62 62 62 168 124 44 206 145 10 224 166 10
++236 178 12 239 182 13 242 186 14 242 186 14
++246 186 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 236 178 12 216 158 10 175 118 6
++ 80 54 7 2 2 6 6 6 6 30 30 30
++ 54 54 54 62 62 62 50 50 50 38 38 38
++ 14 14 14 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 6 6 6 80 54 7 167 114 7
++213 154 11 236 178 12 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 190 14 242 186 14 239 182 13 239 182 13
++230 174 11 210 150 10 174 135 50 124 112 88
++ 82 82 82 54 54 54 34 34 34 18 18 18
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 6 6 6 18 18 18
++ 50 50 50 158 118 36 192 133 9 200 144 11
++216 158 10 219 162 10 224 166 10 226 170 11
++230 174 11 236 178 12 239 182 13 239 182 13
++242 186 14 246 186 14 246 190 14 246 190 14
++246 190 14 246 190 14 246 190 14 246 190 14
++246 186 14 230 174 11 210 150 10 163 110 8
++104 69 6 10 10 10 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 6 6 6 91 60 6 167 114 7
++206 145 10 230 174 11 242 186 14 246 190 14
++246 190 14 246 190 14 246 186 14 242 186 14
++239 182 13 230 174 11 224 166 10 213 154 11
++180 133 36 124 112 88 86 86 86 58 58 58
++ 38 38 38 22 22 22 10 10 10 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 14 14 14
++ 34 34 34 70 70 70 138 110 50 158 118 36
++167 114 7 180 123 7 192 133 9 197 138 11
++200 144 11 206 145 10 213 154 11 219 162 10
++224 166 10 230 174 11 239 182 13 242 186 14
++246 186 14 246 186 14 246 186 14 246 186 14
++239 182 13 216 158 10 185 133 11 152 99 6
++104 69 6 18 14 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 2 2 6 2 2 6 2 2 6
++ 2 2 6 6 6 6 80 54 7 152 99 6
++192 133 9 219 162 10 236 178 12 239 182 13
++246 186 14 242 186 14 239 182 13 236 178 12
++224 166 10 206 145 10 192 133 9 154 121 60
++ 94 94 94 62 62 62 42 42 42 22 22 22
++ 14 14 14 6 6 6 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 18 18 18 34 34 34 58 58 58 78 78 78
++101 98 89 124 112 88 142 110 46 156 107 11
++163 110 8 167 114 7 175 118 6 180 123 7
++185 133 11 197 138 11 210 150 10 219 162 10
++226 170 11 236 178 12 236 178 12 234 174 13
++219 162 10 197 138 11 163 110 8 130 83 6
++ 91 60 6 10 10 10 2 2 6 2 2 6
++ 18 18 18 38 38 38 38 38 38 38 38 38
++ 38 38 38 38 38 38 38 38 38 38 38 38
++ 38 38 38 38 38 38 26 26 26 2 2 6
++ 2 2 6 6 6 6 70 47 6 137 92 6
++175 118 6 200 144 11 219 162 10 230 174 11
++234 174 13 230 174 11 219 162 10 210 150 10
++192 133 9 163 110 8 124 112 88 82 82 82
++ 50 50 50 30 30 30 14 14 14 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 6 6 6 14 14 14 22 22 22 34 34 34
++ 42 42 42 58 58 58 74 74 74 86 86 86
++101 98 89 122 102 70 130 98 46 121 87 25
++137 92 6 152 99 6 163 110 8 180 123 7
++185 133 11 197 138 11 206 145 10 200 144 11
++180 123 7 156 107 11 130 83 6 104 69 6
++ 50 34 6 54 54 54 110 110 110 101 98 89
++ 86 86 86 82 82 82 78 78 78 78 78 78
++ 78 78 78 78 78 78 78 78 78 78 78 78
++ 78 78 78 82 82 82 86 86 86 94 94 94
++106 106 106 101 101 101 86 66 34 124 80 6
++156 107 11 180 123 7 192 133 9 200 144 11
++206 145 10 200 144 11 192 133 9 175 118 6
++139 102 15 109 106 95 70 70 70 42 42 42
++ 22 22 22 10 10 10 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 6 6 6 10 10 10
++ 14 14 14 22 22 22 30 30 30 38 38 38
++ 50 50 50 62 62 62 74 74 74 90 90 90
++101 98 89 112 100 78 121 87 25 124 80 6
++137 92 6 152 99 6 152 99 6 152 99 6
++138 86 6 124 80 6 98 70 6 86 66 30
++101 98 89 82 82 82 58 58 58 46 46 46
++ 38 38 38 34 34 34 34 34 34 34 34 34
++ 34 34 34 34 34 34 34 34 34 34 34 34
++ 34 34 34 34 34 34 38 38 38 42 42 42
++ 54 54 54 82 82 82 94 86 76 91 60 6
++134 86 6 156 107 11 167 114 7 175 118 6
++175 118 6 167 114 7 152 99 6 121 87 25
++101 98 89 62 62 62 34 34 34 18 18 18
++ 6 6 6 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 6 6 6 6 6 6 10 10 10
++ 18 18 18 22 22 22 30 30 30 42 42 42
++ 50 50 50 66 66 66 86 86 86 101 98 89
++106 86 58 98 70 6 104 69 6 104 69 6
++104 69 6 91 60 6 82 62 34 90 90 90
++ 62 62 62 38 38 38 22 22 22 14 14 14
++ 10 10 10 10 10 10 10 10 10 10 10 10
++ 10 10 10 10 10 10 6 6 6 10 10 10
++ 10 10 10 10 10 10 10 10 10 14 14 14
++ 22 22 22 42 42 42 70 70 70 89 81 66
++ 80 54 7 104 69 6 124 80 6 137 92 6
++134 86 6 116 81 8 100 82 52 86 86 86
++ 58 58 58 30 30 30 14 14 14 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 6 6 6 10 10 10 14 14 14
++ 18 18 18 26 26 26 38 38 38 54 54 54
++ 70 70 70 86 86 86 94 86 76 89 81 66
++ 89 81 66 86 86 86 74 74 74 50 50 50
++ 30 30 30 14 14 14 6 6 6 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 6 6 6 18 18 18 34 34 34 58 58 58
++ 82 82 82 89 81 66 89 81 66 89 81 66
++ 94 86 66 94 86 76 74 74 74 50 50 50
++ 26 26 26 14 14 14 6 6 6 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 6 6 6 6 6 6 14 14 14 18 18 18
++ 30 30 30 38 38 38 46 46 46 54 54 54
++ 50 50 50 42 42 42 30 30 30 18 18 18
++ 10 10 10 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 6 6 6 14 14 14 26 26 26
++ 38 38 38 50 50 50 58 58 58 58 58 58
++ 54 54 54 42 42 42 30 30 30 18 18 18
++ 10 10 10 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 6 6 6 10 10 10 14 14 14 18 18 18
++ 18 18 18 14 14 14 10 10 10 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 6 6 6
++ 14 14 14 18 18 18 22 22 22 22 22 22
++ 18 18 18 14 14 14 10 10 10 6 6 6
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
++ 0 0 0 0 0 0 0 0 0 0 0 0
+diff -Naur linux-2.6.29/fs/Kconfig linux-2.6.29-v2010041601/fs/Kconfig
+--- linux-2.6.29/fs/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -209,6 +209,10 @@
+ source "fs/befs/Kconfig"
+ source "fs/bfs/Kconfig"
+ source "fs/efs/Kconfig"
++
++# Patched by YAFFS
++source "fs/yaffs2/Kconfig"
++
+ source "fs/jffs2/Kconfig"
+ # UBIFS File system configuration
+ source "fs/ubifs/Kconfig"
+diff -Naur linux-2.6.29/fs/Makefile linux-2.6.29-v2010041601/fs/Makefile
+--- linux-2.6.29/fs/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -124,3 +124,6 @@
+ obj-$(CONFIG_OCFS2_FS) += ocfs2/
+ obj-$(CONFIG_BTRFS_FS) += btrfs/
+ obj-$(CONFIG_GFS2_FS) += gfs2/
++
++# Patched by YAFFS
++obj-$(CONFIG_YAFFS_FS) += yaffs2/
+diff -Naur linux-2.6.29/fs/yaffs2/devextras.h linux-2.6.29-v2010041601/fs/yaffs2/devextras.h
+--- linux-2.6.29/fs/yaffs2/devextras.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/devextras.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,196 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * This file is just holds extra declarations of macros that would normally
++ * be providesd in the Linux kernel. These macros have been written from
++ * scratch but are functionally equivalent to the Linux ones.
++ *
++ */
++
++#ifndef __EXTRAS_H__
++#define __EXTRAS_H__
++
++
++#if !(defined __KERNEL__)
++
++/* Definition of types */
++typedef unsigned char __u8;
++typedef unsigned short __u16;
++typedef unsigned __u32;
++
++#endif
++
++/*
++ * This is a simple doubly linked list implementation that matches the
++ * way the Linux kernel doubly linked list implementation works.
++ */
++
++struct ylist_head {
++ struct ylist_head *next; /* next in chain */
++ struct ylist_head *prev; /* previous in chain */
++};
++
++
++/* Initialise a static list */
++#define YLIST_HEAD(name) \
++struct ylist_head name = { &(name), &(name)}
++
++
++
++/* Initialise a list head to an empty list */
++#define YINIT_LIST_HEAD(p) \
++do { \
++ (p)->next = (p);\
++ (p)->prev = (p); \
++} while (0)
++
++
++/* Add an element to a list */
++static __inline__ void ylist_add(struct ylist_head *newEntry,
++ struct ylist_head *list)
++{
++ struct ylist_head *listNext = list->next;
++
++ list->next = newEntry;
++ newEntry->prev = list;
++ newEntry->next = listNext;
++ listNext->prev = newEntry;
++
++}
++
++static __inline__ void ylist_add_tail(struct ylist_head *newEntry,
++ struct ylist_head *list)
++{
++ struct ylist_head *listPrev = list->prev;
++
++ list->prev = newEntry;
++ newEntry->next = list;
++ newEntry->prev = listPrev;
++ listPrev->next = newEntry;
++
++}
++
++
++/* Take an element out of its current list, with or without
++ * reinitialising the links.of the entry*/
++static __inline__ void ylist_del(struct ylist_head *entry)
++{
++ struct ylist_head *listNext = entry->next;
++ struct ylist_head *listPrev = entry->prev;
++
++ listNext->prev = listPrev;
++ listPrev->next = listNext;
++
++}
++
++static __inline__ void ylist_del_init(struct ylist_head *entry)
++{
++ ylist_del(entry);
++ entry->next = entry->prev = entry;
++}
++
++
++/* Test if the list is empty */
++static __inline__ int ylist_empty(struct ylist_head *entry)
++{
++ return (entry->next == entry);
++}
++
++
++/* ylist_entry takes a pointer to a list entry and offsets it to that
++ * we can find a pointer to the object it is embedded in.
++ */
++
++
++#define ylist_entry(entry, type, member) \
++ ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
++
++
++/* ylist_for_each and list_for_each_safe iterate over lists.
++ * ylist_for_each_safe uses temporary storage to make the list delete safe
++ */
++
++#define ylist_for_each(itervar, list) \
++ for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
++
++#define ylist_for_each_safe(itervar, saveVar, list) \
++ for (itervar = (list)->next, saveVar = (list)->next->next; \
++ itervar != (list); itervar = saveVar, saveVar = saveVar->next)
++
++
++#if !(defined __KERNEL__)
++
++
++#ifndef WIN32
++#include <sys/stat.h>
++#endif
++
++
++#ifdef CONFIG_YAFFS_PROVIDE_DEFS
++/* File types */
++
++
++#define DT_UNKNOWN 0
++#define DT_FIFO 1
++#define DT_CHR 2
++#define DT_DIR 4
++#define DT_BLK 6
++#define DT_REG 8
++#define DT_LNK 10
++#define DT_SOCK 12
++#define DT_WHT 14
++
++
++#ifndef WIN32
++#include <sys/stat.h>
++#endif
++
++/*
++ * Attribute flags. These should be or-ed together to figure out what
++ * has been changed!
++ */
++#define ATTR_MODE 1
++#define ATTR_UID 2
++#define ATTR_GID 4
++#define ATTR_SIZE 8
++#define ATTR_ATIME 16
++#define ATTR_MTIME 32
++#define ATTR_CTIME 64
++
++struct iattr {
++ unsigned int ia_valid;
++ unsigned ia_mode;
++ unsigned ia_uid;
++ unsigned ia_gid;
++ unsigned ia_size;
++ unsigned ia_atime;
++ unsigned ia_mtime;
++ unsigned ia_ctime;
++ unsigned int ia_attr_flags;
++};
++
++#endif
++
++#else
++
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/stat.h>
++
++#endif
++
++
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/Kconfig linux-2.6.29-v2010041601/fs/yaffs2/Kconfig
+--- linux-2.6.29/fs/yaffs2/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,177 @@
++#
++# YAFFS file system configurations
++#
++
++config YAFFS_FS
++ tristate "YAFFS2 file system support"
++ default n
++ depends on MTD_BLOCK
++ select YAFFS_YAFFS1
++ select YAFFS_YAFFS2
++ help
++ YAFFS2, or Yet Another Flash Filing System, is a filing system
++ optimised for NAND Flash chips.
++
++ To compile the YAFFS2 file system support as a module, choose M
++ here: the module will be called yaffs2.
++
++ If unsure, say N.
++
++ Further information on YAFFS2 is available at
++ <http://www.aleph1.co.uk/yaffs/>.
++
++config YAFFS_YAFFS1
++ bool "512 byte / page devices"
++ depends on YAFFS_FS
++ default y
++ help
++ Enable YAFFS1 support -- yaffs for 512 byte / page devices
++
++ Not needed for 2K-page devices.
++
++ If unsure, say Y.
++
++config YAFFS_9BYTE_TAGS
++ bool "Use older-style on-NAND data format with pageStatus byte"
++ depends on YAFFS_YAFFS1
++ default n
++ help
++
++ Older-style on-NAND data format has a "pageStatus" byte to record
++ chunk/page state. This byte is zero when the page is discarded.
++ Choose this option if you have existing on-NAND data using this
++ format that you need to continue to support. New data written
++ also uses the older-style format. Note: Use of this option
++ generally requires that MTD's oob layout be adjusted to use the
++ older-style format. See notes on tags formats and MTD versions
++ in yaffs_mtdif1.c.
++
++ If unsure, say N.
++
++config YAFFS_DOES_ECC
++ bool "Lets Yaffs do its own ECC"
++ depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
++ default n
++ help
++ This enables Yaffs to use its own ECC functions instead of using
++ the ones from the generic MTD-NAND driver.
++
++ If unsure, say N.
++
++config YAFFS_ECC_WRONG_ORDER
++ bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
++ depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
++ default n
++ help
++ This makes yaffs_ecc.c use the same ecc byte order as Steven
++ Hill's nand_ecc.c. If not set, then you get the same ecc byte
++ order as SmartMedia.
++
++ If unsure, say N.
++
++config YAFFS_YAFFS2
++ bool "2048 byte (or larger) / page devices"
++ depends on YAFFS_FS
++ default y
++ help
++ Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
++
++ If unsure, say Y.
++
++config YAFFS_AUTO_YAFFS2
++ bool "Autoselect yaffs2 format"
++ depends on YAFFS_YAFFS2
++ default y
++ help
++ Without this, you need to explicitely use yaffs2 as the file
++ system type. With this, you can say "yaffs" and yaffs or yaffs2
++ will be used depending on the device page size (yaffs on
++ 512-byte page devices, yaffs2 on 2K page devices).
++
++ If unsure, say Y.
++
++config YAFFS_DISABLE_TAGS_ECC
++ bool "Disable YAFFS from doing ECC on tags by default"
++ depends on YAFFS_FS && YAFFS_YAFFS2
++ default n
++ help
++ This defaults Yaffs to using its own ECC calculations on tags instead of
++ just relying on the MTD.
++ This behavior can also be overridden with tags_ecc_on and
++ tags_ecc_off mount options.
++
++ If unsure, say N.
++
++config YAFFS_DISABLE_LAZY_LOAD
++ bool "Disable lazy loading"
++ depends on YAFFS_YAFFS2
++ default n
++ help
++ "Lazy loading" defers loading file details until they are
++ required. This saves mount time, but makes the first look-up
++ a bit longer.
++
++ Lazy loading will only happen if enabled by this option being 'n'
++ and if the appropriate tags are available, else yaffs2 will
++ automatically fall back to immediate loading and do the right
++ thing.
++
++ Lazy laoding will be required by checkpointing.
++
++ Setting this to 'y' will disable lazy loading.
++
++ If unsure, say N.
++
++
++config YAFFS_DISABLE_WIDE_TNODES
++ bool "Turn off wide tnodes"
++ depends on YAFFS_FS
++ default n
++ help
++ Wide tnodes are only used for NAND arrays >=32MB for 512-byte
++ page devices and >=128MB for 2k page devices. They use slightly
++ more RAM but are faster since they eliminate chunk group
++ searching.
++
++ Setting this to 'y' will force tnode width to 16 bits and save
++ memory but make large arrays slower.
++
++ If unsure, say N.
++
++config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
++ bool "Force chunk erase check"
++ depends on YAFFS_FS
++ default n
++ help
++ Normally YAFFS only checks chunks before writing until an erased
++ chunk is found. This helps to detect any partially written
++ chunks that might have happened due to power loss.
++
++ Enabling this forces on the test that chunks are erased in flash
++ before writing to them. This takes more time but is potentially
++ a bit more secure.
++
++ Suggest setting Y during development and ironing out driver
++ issues etc. Suggest setting to N if you want faster writing.
++
++ If unsure, say Y.
++
++config YAFFS_SHORT_NAMES_IN_RAM
++ bool "Cache short names in RAM"
++ depends on YAFFS_FS
++ default y
++ help
++ If this config is set, then short names are stored with the
++ yaffs_Object. This costs an extra 16 bytes of RAM per object,
++ but makes look-ups faster.
++
++ If unsure, say Y.
++
++config YAFFS_EMPTY_LOST_AND_FOUND
++ bool "Empty lost and found on boot"
++ depends on YAFFS_FS
++ default n
++ help
++ If this is enabled then the contents of lost and found is
++ automatically dumped at mount.
++
+diff -Naur linux-2.6.29/fs/yaffs2/Makefile linux-2.6.29-v2010041601/fs/yaffs2/Makefile
+--- linux-2.6.29/fs/yaffs2/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,10 @@
++#
++# Makefile for the linux YAFFS filesystem routines.
++#
++
++obj-$(CONFIG_YAFFS_FS) += yaffs.o
++
++yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
++yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
++yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
+diff -Naur linux-2.6.29/fs/yaffs2/moduleconfig.h linux-2.6.29-v2010041601/fs/yaffs2/moduleconfig.h
+--- linux-2.6.29/fs/yaffs2/moduleconfig.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/moduleconfig.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,75 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Martin Fouts <Martin.Fouts@palmsource.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_CONFIG_H__
++#define __YAFFS_CONFIG_H__
++
++#ifdef YAFFS_OUT_OF_TREE
++
++/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */
++#define CONFIG_YAFFS_FS
++#define CONFIG_YAFFS_YAFFS1
++#define CONFIG_YAFFS_YAFFS2
++
++/* These options are independent of each other. Select those that matter. */
++
++/* Default: Not selected */
++/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
++/* #define CONFIG_YAFFS_DOES_ECC */
++
++/* Default: Selected */
++/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */
++#define CONFIG_YAFFS_DOES_TAGS_ECC
++
++/* Default: Not selected */
++/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
++/* CONFIG_YAFFS_DOES_ECC is set */
++/* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
++
++/* Default: Selected */
++/* Meaning: Disables testing whether chunks are erased before writing to them*/
++#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
++
++/* Default: Not Selected */
++/* Meaning: At mount automatically empty all files from lost and found. */
++/* This is done to fix an old problem where rmdir was not checking for an */
++/* empty directory. This can also be achieved with a mount option. */
++/* #define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND */
++
++/* Default: Selected */
++/* Meaning: Cache short names, taking more RAM, but faster look-ups */
++#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
++
++/* Default: 10 */
++/* Meaning: set the count of blocks to reserve for checkpointing */
++#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
++
++/*
++Older-style on-NAND data format has a "pageStatus" byte to record
++chunk/page state. This byte is zeroed when the page is discarded.
++Choose this option if you have existing on-NAND data in this format
++that you need to continue to support. New data written also uses the
++older-style format.
++Note: Use of this option generally requires that MTD's oob layout be
++adjusted to use the older-style format. See notes on tags formats and
++MTD versions in yaffs_mtdif1.c.
++*/
++/* Default: Not selected */
++/* Meaning: Use older-style on-NAND data format with pageStatus byte */
++/* #define CONFIG_YAFFS_9BYTE_TAGS */
++
++#endif /* YAFFS_OUT_OF_TREE */
++
++#endif /* __YAFFS_CONFIG_H__ */
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_checkptrw.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_checkptrw.c
+--- linux-2.6.29/fs/yaffs2/yaffs_checkptrw.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_checkptrw.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,405 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++const char *yaffs_checkptrw_c_version =
++ "$Id: yaffs_checkptrw.c,v 1.22 2009-11-03 02:36:30 charles Exp $";
++
++
++#include "yaffs_checkptrw.h"
++#include "yaffs_getblockinfo.h"
++
++static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
++{
++ int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
++
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("checkpt blocks available = %d" TENDSTR),
++ blocksAvailable));
++
++ return (blocksAvailable <= 0) ? 0 : 1;
++}
++
++
++static int yaffs_CheckpointErase(yaffs_Device *dev)
++{
++ int i;
++
++ if (!dev->eraseBlockInNAND)
++ return 0;
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
++ dev->internalStartBlock, dev->internalEndBlock));
++
++ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
++ if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
++
++ dev->nBlockErasures++;
++
++ if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
++ bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
++ dev->nErasedBlocks++;
++ dev->nFreeChunks += dev->nChunksPerBlock;
++ } else {
++ dev->markNANDBlockBad(dev, i);
++ bi->blockState = YAFFS_BLOCK_STATE_DEAD;
++ }
++ }
++ }
++
++ dev->blocksInCheckpoint = 0;
++
++ return 1;
++}
++
++
++static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
++{
++ int i;
++ int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
++ T(YAFFS_TRACE_CHECKPOINT,
++ (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
++ dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
++
++ if (dev->checkpointNextBlock >= 0 &&
++ dev->checkpointNextBlock <= dev->internalEndBlock &&
++ blocksAvailable > 0) {
++
++ for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
++ if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
++ dev->checkpointNextBlock = i + 1;
++ dev->checkpointCurrentBlock = i;
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i));
++ return;
++ }
++ }
++ }
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR)));
++
++ dev->checkpointNextBlock = -1;
++ dev->checkpointCurrentBlock = -1;
++}
++
++static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
++{
++ int i;
++ yaffs_ExtendedTags tags;
++
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
++ dev->blocksInCheckpoint, dev->checkpointNextBlock));
++
++ if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
++ for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
++ int chunk = i * dev->nChunksPerBlock;
++ int realignedChunk = chunk - dev->chunkOffset;
++
++ dev->readChunkWithTagsFromNAND(dev, realignedChunk,
++ NULL, &tags);
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
++ i, tags.objectId, tags.sequenceNumber, tags.eccResult));
++
++ if (tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
++ /* Right kind of block */
++ dev->checkpointNextBlock = tags.objectId;
++ dev->checkpointCurrentBlock = i;
++ dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
++ dev->blocksInCheckpoint++;
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i));
++ return;
++ }
++ }
++
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR)));
++
++ dev->checkpointNextBlock = -1;
++ dev->checkpointCurrentBlock = -1;
++}
++
++
++int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
++{
++
++
++ dev->checkpointOpenForWrite = forWriting;
++
++ /* Got the functions we need? */
++ if (!dev->writeChunkWithTagsToNAND ||
++ !dev->readChunkWithTagsFromNAND ||
++ !dev->eraseBlockInNAND ||
++ !dev->markNANDBlockBad)
++ return 0;
++
++ if (forWriting && !yaffs_CheckpointSpaceOk(dev))
++ return 0;
++
++ if (!dev->checkpointBuffer)
++ dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
++ if (!dev->checkpointBuffer)
++ return 0;
++
++
++ dev->checkpointPageSequence = 0;
++ dev->checkpointByteCount = 0;
++ dev->checkpointSum = 0;
++ dev->checkpointXor = 0;
++ dev->checkpointCurrentBlock = -1;
++ dev->checkpointCurrentChunk = -1;
++ dev->checkpointNextBlock = dev->internalStartBlock;
++
++ /* Erase all the blocks in the checkpoint area */
++ if (forWriting) {
++ memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
++ dev->checkpointByteOffset = 0;
++ return yaffs_CheckpointErase(dev);
++ } else {
++ int i;
++ /* Set to a value that will kick off a read */
++ dev->checkpointByteOffset = dev->nDataBytesPerChunk;
++ /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
++ * going to be way more than we need */
++ dev->blocksInCheckpoint = 0;
++ dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
++ dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
++ if(!dev->checkpointBlockList)
++ return 0;
++
++ for (i = 0; i < dev->checkpointMaxBlocks; i++)
++ dev->checkpointBlockList[i] = -1;
++ }
++
++ return 1;
++}
++
++int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
++{
++ __u32 compositeSum;
++ compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
++ *sum = compositeSum;
++ return 1;
++}
++
++static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
++{
++ int chunk;
++ int realignedChunk;
++
++ yaffs_ExtendedTags tags;
++
++ if (dev->checkpointCurrentBlock < 0) {
++ yaffs_CheckpointFindNextErasedBlock(dev);
++ dev->checkpointCurrentChunk = 0;
++ }
++
++ if (dev->checkpointCurrentBlock < 0)
++ return 0;
++
++ tags.chunkDeleted = 0;
++ tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
++ tags.chunkId = dev->checkpointPageSequence + 1;
++ tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
++ tags.byteCount = dev->nDataBytesPerChunk;
++ if (dev->checkpointCurrentChunk == 0) {
++ /* First chunk we write for the block? Set block state to
++ checkpoint */
++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointCurrentBlock);
++ bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
++ dev->blocksInCheckpoint++;
++ }
++
++ chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
++
++
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
++ chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk, tags.objectId, tags.chunkId));
++
++ realignedChunk = chunk - dev->chunkOffset;
++
++ dev->nPageWrites++;
++
++ dev->writeChunkWithTagsToNAND(dev, realignedChunk,
++ dev->checkpointBuffer, &tags);
++ dev->checkpointByteOffset = 0;
++ dev->checkpointPageSequence++;
++ dev->checkpointCurrentChunk++;
++ if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {
++ dev->checkpointCurrentChunk = 0;
++ dev->checkpointCurrentBlock = -1;
++ }
++ memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
++
++ return 1;
++}
++
++
++int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
++{
++ int i = 0;
++ int ok = 1;
++
++
++ __u8 * dataBytes = (__u8 *)data;
++
++
++
++ if (!dev->checkpointBuffer)
++ return 0;
++
++ if (!dev->checkpointOpenForWrite)
++ return -1;
++
++ while (i < nBytes && ok) {
++ dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes;
++ dev->checkpointSum += *dataBytes;
++ dev->checkpointXor ^= *dataBytes;
++
++ dev->checkpointByteOffset++;
++ i++;
++ dataBytes++;
++ dev->checkpointByteCount++;
++
++
++ if (dev->checkpointByteOffset < 0 ||
++ dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
++ ok = yaffs_CheckpointFlushBuffer(dev);
++ }
++
++ return i;
++}
++
++int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
++{
++ int i = 0;
++ int ok = 1;
++ yaffs_ExtendedTags tags;
++
++
++ int chunk;
++ int realignedChunk;
++
++ __u8 *dataBytes = (__u8 *)data;
++
++ if (!dev->checkpointBuffer)
++ return 0;
++
++ if (dev->checkpointOpenForWrite)
++ return -1;
++
++ while (i < nBytes && ok) {
++
++
++ if (dev->checkpointByteOffset < 0 ||
++ dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
++
++ if (dev->checkpointCurrentBlock < 0) {
++ yaffs_CheckpointFindNextCheckpointBlock(dev);
++ dev->checkpointCurrentChunk = 0;
++ }
++
++ if (dev->checkpointCurrentBlock < 0)
++ ok = 0;
++ else {
++ chunk = dev->checkpointCurrentBlock *
++ dev->nChunksPerBlock +
++ dev->checkpointCurrentChunk;
++
++ realignedChunk = chunk - dev->chunkOffset;
++
++ dev->nPageReads++;
++
++ /* read in the next chunk */
++ /* printf("read checkpoint page %d\n",dev->checkpointPage); */
++ dev->readChunkWithTagsFromNAND(dev,
++ realignedChunk,
++ dev->checkpointBuffer,
++ &tags);
++
++ if (tags.chunkId != (dev->checkpointPageSequence + 1) ||
++ tags.eccResult > YAFFS_ECC_RESULT_FIXED ||
++ tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
++ ok = 0;
++
++ dev->checkpointByteOffset = 0;
++ dev->checkpointPageSequence++;
++ dev->checkpointCurrentChunk++;
++
++ if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
++ dev->checkpointCurrentBlock = -1;
++ }
++ }
++
++ if (ok) {
++ *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
++ dev->checkpointSum += *dataBytes;
++ dev->checkpointXor ^= *dataBytes;
++ dev->checkpointByteOffset++;
++ i++;
++ dataBytes++;
++ dev->checkpointByteCount++;
++ }
++ }
++
++ return i;
++}
++
++int yaffs_CheckpointClose(yaffs_Device *dev)
++{
++
++ if (dev->checkpointOpenForWrite) {
++ if (dev->checkpointByteOffset != 0)
++ yaffs_CheckpointFlushBuffer(dev);
++ } else if(dev->checkpointBlockList){
++ int i;
++ for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
++ int blk = dev->checkpointBlockList[i];
++ yaffs_BlockInfo *bi = NULL;
++ if( dev->internalStartBlock <= blk && blk <= dev->internalEndBlock)
++ bi = yaffs_GetBlockInfo(dev, blk);
++ if (bi && bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
++ bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
++ else {
++ /* Todo this looks odd... */
++ }
++ }
++ YFREE(dev->checkpointBlockList);
++ dev->checkpointBlockList = NULL;
++ }
++
++ dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
++ dev->nErasedBlocks -= dev->blocksInCheckpoint;
++
++
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR),
++ dev->checkpointByteCount));
++
++ if (dev->checkpointBuffer) {
++ /* free the buffer */
++ YFREE(dev->checkpointBuffer);
++ dev->checkpointBuffer = NULL;
++ return 1;
++ } else
++ return 0;
++}
++
++int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
++{
++ /* Erase the checkpoint data */
++
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
++ dev->blocksInCheckpoint));
++
++ return yaffs_CheckpointErase(dev);
++}
++
++
++
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_checkptrw.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_checkptrw.h
+--- linux-2.6.29/fs/yaffs2/yaffs_checkptrw.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_checkptrw.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,35 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_CHECKPTRW_H__
++#define __YAFFS_CHECKPTRW_H__
++
++#include "yaffs_guts.h"
++
++int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
++
++int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
++
++int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
++
++int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
++
++int yaffs_CheckpointClose(yaffs_Device *dev);
++
++int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
++
++
++#endif
++
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_ecc.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_ecc.c
+--- linux-2.6.29/fs/yaffs2/yaffs_ecc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_ecc.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,326 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can 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 code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
++ * blocks are used on a 512-byte NAND page.
++ *
++ */
++
++/* Table generated by gen-ecc.c
++ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
++ * for each byte of data. These are instead provided in a table in bits7..2.
++ * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
++ * this bytes influence on the line parity.
++ */
++
++const char *yaffs_ecc_c_version =
++ "$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $";
++
++#include "yportenv.h"
++
++#include "yaffs_ecc.h"
++
++static const unsigned char column_parity_table[] = {
++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++};
++
++/* Count the bits in an unsigned char or a U32 */
++
++static int yaffs_CountBits(unsigned char x)
++{
++ int r = 0;
++ while (x) {
++ if (x & 1)
++ r++;
++ x >>= 1;
++ }
++ return r;
++}
++
++static int yaffs_CountBits32(unsigned x)
++{
++ int r = 0;
++ while (x) {
++ if (x & 1)
++ r++;
++ x >>= 1;
++ }
++ return r;
++}
++
++/* Calculate the ECC for a 256-byte block of data */
++void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
++{
++ unsigned int i;
++
++ unsigned char col_parity = 0;
++ unsigned char line_parity = 0;
++ unsigned char line_parity_prime = 0;
++ unsigned char t;
++ unsigned char b;
++
++ for (i = 0; i < 256; i++) {
++ b = column_parity_table[*data++];
++ col_parity ^= b;
++
++ if (b & 0x01) { /* odd number of bits in the byte */
++ line_parity ^= i;
++ line_parity_prime ^= ~i;
++ }
++ }
++
++ ecc[2] = (~col_parity) | 0x03;
++
++ t = 0;
++ if (line_parity & 0x80)
++ t |= 0x80;
++ if (line_parity_prime & 0x80)
++ t |= 0x40;
++ if (line_parity & 0x40)
++ t |= 0x20;
++ if (line_parity_prime & 0x40)
++ t |= 0x10;
++ if (line_parity & 0x20)
++ t |= 0x08;
++ if (line_parity_prime & 0x20)
++ t |= 0x04;
++ if (line_parity & 0x10)
++ t |= 0x02;
++ if (line_parity_prime & 0x10)
++ t |= 0x01;
++ ecc[1] = ~t;
++
++ t = 0;
++ if (line_parity & 0x08)
++ t |= 0x80;
++ if (line_parity_prime & 0x08)
++ t |= 0x40;
++ if (line_parity & 0x04)
++ t |= 0x20;
++ if (line_parity_prime & 0x04)
++ t |= 0x10;
++ if (line_parity & 0x02)
++ t |= 0x08;
++ if (line_parity_prime & 0x02)
++ t |= 0x04;
++ if (line_parity & 0x01)
++ t |= 0x02;
++ if (line_parity_prime & 0x01)
++ t |= 0x01;
++ ecc[0] = ~t;
++
++#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
++ /* Swap the bytes into the wrong order */
++ t = ecc[0];
++ ecc[0] = ecc[1];
++ ecc[1] = t;
++#endif
++}
++
++
++/* Correct the ECC on a 256 byte block of data */
++
++int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
++ const unsigned char *test_ecc)
++{
++ unsigned char d0, d1, d2; /* deltas */
++
++ d0 = read_ecc[0] ^ test_ecc[0];
++ d1 = read_ecc[1] ^ test_ecc[1];
++ d2 = read_ecc[2] ^ test_ecc[2];
++
++ if ((d0 | d1 | d2) == 0)
++ return 0; /* no error */
++
++ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
++ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
++ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
++ /* Single bit (recoverable) error in data */
++
++ unsigned byte;
++ unsigned bit;
++
++#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
++ /* swap the bytes to correct for the wrong order */
++ unsigned char t;
++
++ t = d0;
++ d0 = d1;
++ d1 = t;
++#endif
++
++ bit = byte = 0;
++
++ if (d1 & 0x80)
++ byte |= 0x80;
++ if (d1 & 0x20)
++ byte |= 0x40;
++ if (d1 & 0x08)
++ byte |= 0x20;
++ if (d1 & 0x02)
++ byte |= 0x10;
++ if (d0 & 0x80)
++ byte |= 0x08;
++ if (d0 & 0x20)
++ byte |= 0x04;
++ if (d0 & 0x08)
++ byte |= 0x02;
++ if (d0 & 0x02)
++ byte |= 0x01;
++
++ if (d2 & 0x80)
++ bit |= 0x04;
++ if (d2 & 0x20)
++ bit |= 0x02;
++ if (d2 & 0x08)
++ bit |= 0x01;
++
++ data[byte] ^= (1 << bit);
++
++ return 1; /* Corrected the error */
++ }
++
++ if ((yaffs_CountBits(d0) +
++ yaffs_CountBits(d1) +
++ yaffs_CountBits(d2)) == 1) {
++ /* Reccoverable error in ecc */
++
++ read_ecc[0] = test_ecc[0];
++ read_ecc[1] = test_ecc[1];
++ read_ecc[2] = test_ecc[2];
++
++ return 1; /* Corrected the error */
++ }
++
++ /* Unrecoverable error */
++
++ return -1;
++
++}
++
++
++/*
++ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
++ */
++void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
++ yaffs_ECCOther *eccOther)
++{
++ unsigned int i;
++
++ unsigned char col_parity = 0;
++ unsigned line_parity = 0;
++ unsigned line_parity_prime = 0;
++ unsigned char b;
++
++ for (i = 0; i < nBytes; i++) {
++ b = column_parity_table[*data++];
++ col_parity ^= b;
++
++ if (b & 0x01) {
++ /* odd number of bits in the byte */
++ line_parity ^= i;
++ line_parity_prime ^= ~i;
++ }
++
++ }
++
++ eccOther->colParity = (col_parity >> 2) & 0x3f;
++ eccOther->lineParity = line_parity;
++ eccOther->lineParityPrime = line_parity_prime;
++}
++
++int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
++ yaffs_ECCOther *read_ecc,
++ const yaffs_ECCOther *test_ecc)
++{
++ unsigned char cDelta; /* column parity delta */
++ unsigned lDelta; /* line parity delta */
++ unsigned lDeltaPrime; /* line parity delta */
++ unsigned bit;
++
++ cDelta = read_ecc->colParity ^ test_ecc->colParity;
++ lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
++ lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
++
++ if ((cDelta | lDelta | lDeltaPrime) == 0)
++ return 0; /* no error */
++
++ if (lDelta == ~lDeltaPrime &&
++ (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) {
++ /* Single bit (recoverable) error in data */
++
++ bit = 0;
++
++ if (cDelta & 0x20)
++ bit |= 0x04;
++ if (cDelta & 0x08)
++ bit |= 0x02;
++ if (cDelta & 0x02)
++ bit |= 0x01;
++
++ if (lDelta >= nBytes)
++ return -1;
++
++ data[lDelta] ^= (1 << bit);
++
++ return 1; /* corrected */
++ }
++
++ if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
++ yaffs_CountBits(cDelta)) == 1) {
++ /* Reccoverable error in ecc */
++
++ *read_ecc = *test_ecc;
++ return 1; /* corrected */
++ }
++
++ /* Unrecoverable error */
++
++ return -1;
++}
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_ecc.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_ecc.h
+--- linux-2.6.29/fs/yaffs2/yaffs_ecc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_ecc.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
++ * blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#ifndef __YAFFS_ECC_H__
++#define __YAFFS_ECC_H__
++
++typedef struct {
++ unsigned char colParity;
++ unsigned lineParity;
++ unsigned lineParityPrime;
++} yaffs_ECCOther;
++
++void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
++int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
++ const unsigned char *test_ecc);
++
++void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
++ yaffs_ECCOther *ecc);
++int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
++ yaffs_ECCOther *read_ecc,
++ const yaffs_ECCOther *test_ecc);
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_fs.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_fs.c
+--- linux-2.6.29/fs/yaffs2/yaffs_fs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_fs.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,2806 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2009 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ * Acknowledgements:
++ * Luc van OostenRyck for numerous patches.
++ * Nick Bane for numerous patches.
++ * Nick Bane for 2.5/2.6 integration.
++ * Andras Toth for mknod rdev issue.
++ * Michael Fischer for finding the problem with inode inconsistency.
++ * Some code bodily lifted from JFFS
++ *
++ * This program is free software; you can 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 the file system front-end to YAFFS that hooks it up to
++ * the VFS.
++ *
++ * Special notes:
++ * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
++ * this superblock
++ * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
++ * superblock
++ * >> inode->u.generic_ip points to the associated yaffs_Object.
++ */
++
++const char *yaffs_fs_c_version =
++ "$Id: yaffs_fs.c,v 1.92 2010-01-19 21:16:30 charles Exp $";
++extern const char *yaffs_guts_c_version;
++
++#include <linux/version.h>
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++#include <linux/config.h>
++#endif
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/proc_fs.h>
++#include <linux/smp_lock.h>
++#include <linux/pagemap.h>
++#include <linux/mtd/mtd.h>
++#include <linux/interrupt.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++
++#include "asm/div64.h"
++
++
++#define LOCK_TRACE 0
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++
++#include <linux/statfs.h> /* Added NCB 15-8-2003 */
++#include <linux/statfs.h>
++#define UnlockPage(p) unlock_page(p)
++#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
++
++/* FIXME: use sb->s_id instead ? */
++#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
++
++#else
++
++#include <linux/locks.h>
++#define BDEVNAME_SIZE 0
++#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
++/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
++#define __user
++#endif
++
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
++#define YPROC_ROOT (&proc_root)
++#else
++#define YPROC_ROOT NULL
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++#define WRITE_SIZE_STR "writesize"
++#define WRITE_SIZE(mtd) ((mtd)->writesize)
++#else
++#define WRITE_SIZE_STR "oobblock"
++#define WRITE_SIZE(mtd) ((mtd)->oobblock)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
++#define YAFFS_USE_WRITE_BEGIN_END 1
++#else
++#define YAFFS_USE_WRITE_BEGIN_END 0
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
++static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
++{
++ uint64_t result = partition_size;
++ do_div(result, block_size);
++ return (uint32_t)result;
++}
++#else
++#define YCALCBLOCKS(s, b) ((s)/(b))
++#endif
++
++#include <linux/uaccess.h>
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++
++#include <linux/mtd/mtd.h>
++#include "yaffs_mtdif.h"
++#include "yaffs_mtdif1.h"
++#include "yaffs_mtdif2.h"
++
++unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
++unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
++unsigned int yaffs_auto_checkpoint = 1;
++
++/* Module Parameters */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++module_param(yaffs_traceMask, uint, 0644);
++module_param(yaffs_wr_attempts, uint, 0644);
++module_param(yaffs_auto_checkpoint, uint, 0644);
++#else
++MODULE_PARM(yaffs_traceMask, "i");
++MODULE_PARM(yaffs_wr_attempts, "i");
++MODULE_PARM(yaffs_auto_checkpoint, "i");
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
++/* use iget and read_inode */
++#define Y_IGET(sb, inum) iget((sb), (inum))
++static void yaffs_read_inode(struct inode *inode);
++
++#else
++/* Call local equivalent */
++#define YAFFS_USE_OWN_IGET
++#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
++
++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
++#endif
++
++/*#define T(x) printk x */
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
++#else
++#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
++#endif
++
++#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
++#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
++#else
++#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
++#endif
++
++
++#define update_dir_time(dir) do {\
++ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
++ } while(0)
++
++static void yaffs_put_super(struct super_block *sb);
++
++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
++ loff_t *pos);
++static ssize_t yaffs_hold_space(struct file *f);
++static void yaffs_release_space(struct file *f);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_file_flush(struct file *file, fl_owner_t id);
++#else
++static int yaffs_file_flush(struct file *file);
++#endif
++
++static int yaffs_sync_object(struct file *file, struct dentry *dentry,
++ int datasync);
++
++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
++ struct nameidata *n);
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
++ struct nameidata *n);
++#else
++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
++#endif
++static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
++ struct dentry *dentry);
++static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
++static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
++ const char *symname);
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++ dev_t dev);
++#else
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++ int dev);
++#endif
++static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
++ struct inode *new_dir, struct dentry *new_dentry);
++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_sync_fs(struct super_block *sb, int wait);
++static void yaffs_write_super(struct super_block *sb);
++#else
++static int yaffs_sync_fs(struct super_block *sb);
++static int yaffs_write_super(struct super_block *sb);
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
++#else
++static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
++#endif
++
++#ifdef YAFFS_HAS_PUT_INODE
++static void yaffs_put_inode(struct inode *inode);
++#endif
++
++static void yaffs_delete_inode(struct inode *);
++static void yaffs_clear_inode(struct inode *);
++
++static int yaffs_readpage(struct file *file, struct page *page);
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
++#else
++static int yaffs_writepage(struct page *page);
++#endif
++
++
++#if (YAFFS_USE_WRITE_BEGIN_END != 0)
++static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned flags,
++ struct page **pagep, void **fsdata);
++static int yaffs_write_end(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned copied,
++ struct page *pg, void *fsdadata);
++#else
++static int yaffs_prepare_write(struct file *f, struct page *pg,
++ unsigned offset, unsigned to);
++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
++ unsigned to);
++
++#endif
++
++static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
++ int buflen);
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
++#else
++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
++#endif
++
++static struct address_space_operations yaffs_file_address_operations = {
++ .readpage = yaffs_readpage,
++ .writepage = yaffs_writepage,
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++ .write_begin = yaffs_write_begin,
++ .write_end = yaffs_write_end,
++#else
++ .prepare_write = yaffs_prepare_write,
++ .commit_write = yaffs_commit_write,
++#endif
++};
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
++static const struct file_operations yaffs_file_operations = {
++ .read = do_sync_read,
++ .write = do_sync_write,
++ .aio_read = generic_file_aio_read,
++ .aio_write = generic_file_aio_write,
++ .mmap = generic_file_mmap,
++ .flush = yaffs_file_flush,
++ .fsync = yaffs_sync_object,
++ .splice_read = generic_file_splice_read,
++ .splice_write = generic_file_splice_write,
++ .llseek = generic_file_llseek,
++};
++
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
++
++static const struct file_operations yaffs_file_operations = {
++ .read = do_sync_read,
++ .write = do_sync_write,
++ .aio_read = generic_file_aio_read,
++ .aio_write = generic_file_aio_write,
++ .mmap = generic_file_mmap,
++ .flush = yaffs_file_flush,
++ .fsync = yaffs_sync_object,
++ .sendfile = generic_file_sendfile,
++};
++
++#else
++
++static const struct file_operations yaffs_file_operations = {
++ .read = generic_file_read,
++ .write = generic_file_write,
++ .mmap = generic_file_mmap,
++ .flush = yaffs_file_flush,
++ .fsync = yaffs_sync_object,
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ .sendfile = generic_file_sendfile,
++#endif
++};
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
++static void zero_user_segment(struct page *page, unsigned start, unsigned end)
++{
++ void * kaddr = kmap_atomic(page, KM_USER0);
++ memset(kaddr + start, 0, end - start);
++ kunmap_atomic(kaddr, KM_USER0);
++ flush_dcache_page(page);
++}
++#endif
++
++
++static const struct inode_operations yaffs_file_inode_operations = {
++ .setattr = yaffs_setattr,
++};
++
++static const struct inode_operations yaffs_symlink_inode_operations = {
++ .readlink = yaffs_readlink,
++ .follow_link = yaffs_follow_link,
++ .setattr = yaffs_setattr,
++};
++
++static const struct inode_operations yaffs_dir_inode_operations = {
++ .create = yaffs_create,
++ .lookup = yaffs_lookup,
++ .link = yaffs_link,
++ .unlink = yaffs_unlink,
++ .symlink = yaffs_symlink,
++ .mkdir = yaffs_mkdir,
++ .rmdir = yaffs_unlink,
++ .mknod = yaffs_mknod,
++ .rename = yaffs_rename,
++ .setattr = yaffs_setattr,
++};
++
++static const struct file_operations yaffs_dir_operations = {
++ .read = generic_read_dir,
++ .readdir = yaffs_readdir,
++ .fsync = yaffs_sync_object,
++};
++
++static const struct super_operations yaffs_super_ops = {
++ .statfs = yaffs_statfs,
++
++#ifndef YAFFS_USE_OWN_IGET
++ .read_inode = yaffs_read_inode,
++#endif
++#ifdef YAFFS_HAS_PUT_INODE
++ .put_inode = yaffs_put_inode,
++#endif
++ .put_super = yaffs_put_super,
++ .delete_inode = yaffs_delete_inode,
++ .clear_inode = yaffs_clear_inode,
++ .sync_fs = yaffs_sync_fs,
++ .write_super = yaffs_write_super,
++};
++
++static void yaffs_GrossLock(yaffs_Device *dev)
++{
++ T(LOCK_TRACE && YAFFS_TRACE_OS, ("yaffs locking %p\n", current));
++ down(&dev->grossLock);
++ T(LOCK_TRACE && YAFFS_TRACE_OS, ("yaffs locked %p\n", current));
++}
++
++static void yaffs_GrossUnlock(yaffs_Device *dev)
++{
++ T(LOCK_TRACE && YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current));
++ up(&dev->grossLock);
++}
++
++
++/*-----------------------------------------------------------------*/
++/* Directory search context allows us to unlock access to yaffs during
++ * filldir without causing problems with the directory being modified.
++ * This is similar to the tried and tested mechanism used in yaffs direct.
++ *
++ * A search context iterates along a doubly linked list of siblings in the
++ * directory. If the iterating object is deleted then this would corrupt
++ * the list iteration, likely causing a crash. The search context avoids
++ * this by using the removeObjectCallback to move the search context to the
++ * next object before the object is deleted.
++ *
++ * Many readdirs (and thus seach conexts) may be alive simulateously so
++ * each yaffs_Device has a list of these.
++ *
++ * A seach context lives for the duration of a readdir.
++ *
++ * All these functions must be called while yaffs is locked.
++ */
++
++struct yaffs_SearchContext {
++ yaffs_Device *dev;
++ yaffs_Object *dirObj;
++ yaffs_Object *nextReturn;
++ struct ylist_head others;
++};
++
++/*
++ * yaffs_NewSearch() creates a new search context, initialises it and
++ * adds it to the device's search context list.
++ *
++ * Called at start of readdir.
++ */
++static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_Object *dir)
++{
++ yaffs_Device *dev = dir->myDev;
++ struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
++ if(sc){
++ sc->dirObj = dir;
++ sc->dev = dev;
++ if( ylist_empty(&sc->dirObj->variant.directoryVariant.children))
++ sc->nextReturn = NULL;
++ else
++ sc->nextReturn = ylist_entry(
++ dir->variant.directoryVariant.children.next,
++ yaffs_Object,siblings);
++ YINIT_LIST_HEAD(&sc->others);
++ ylist_add(&sc->others,&dev->searchContexts);
++ }
++ return sc;
++}
++
++/*
++ * yaffs_EndSearch() disposes of a search context and cleans up.
++ */
++static void yaffs_EndSearch(struct yaffs_SearchContext * sc)
++{
++ if(sc){
++ ylist_del(&sc->others);
++ YFREE(sc);
++ }
++}
++
++/*
++ * yaffs_SearchAdvance() moves a search context to the next object.
++ * Called when the search iterates or when an object removal causes
++ * the search context to be moved to the next object.
++ */
++static void yaffs_SearchAdvance(struct yaffs_SearchContext *sc)
++{
++ if(!sc)
++ return;
++
++ if( sc->nextReturn == NULL ||
++ ylist_empty(&sc->dirObj->variant.directoryVariant.children))
++ sc->nextReturn = NULL;
++ else {
++ struct ylist_head *next = sc->nextReturn->siblings.next;
++
++ if( next == &sc->dirObj->variant.directoryVariant.children)
++ sc->nextReturn = NULL; /* end of list */
++ else
++ sc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
++ }
++}
++
++/*
++ * yaffs_RemoveObjectCallback() is called when an object is unlinked.
++ * We check open search contexts and advance any which are currently
++ * on the object being iterated.
++ */
++static void yaffs_RemoveObjectCallback(yaffs_Object *obj)
++{
++
++ struct ylist_head *i;
++ struct yaffs_SearchContext *sc;
++ struct ylist_head *search_contexts = &obj->myDev->searchContexts;
++
++
++ /* Iterate through the directory search contexts.
++ * If any are currently on the object being removed, then advance
++ * the search context to the next object to prevent a hanging pointer.
++ */
++ ylist_for_each(i, search_contexts) {
++ if (i) {
++ sc = ylist_entry(i, struct yaffs_SearchContext,others);
++ if(sc->nextReturn == obj)
++ yaffs_SearchAdvance(sc);
++ }
++ }
++
++}
++
++
++/*-----------------------------------------------------------------*/
++
++static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
++ int buflen)
++{
++ unsigned char *alias;
++ int ret;
++
++ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
++
++ yaffs_GrossLock(dev);
++
++ alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
++
++ yaffs_GrossUnlock(dev);
++
++ if (!alias)
++ return -ENOMEM;
++
++ ret = vfs_readlink(dentry, buffer, buflen, alias);
++ kfree(alias);
++ return ret;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++#else
++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++#endif
++{
++ unsigned char *alias;
++ int ret;
++ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
++
++ yaffs_GrossLock(dev);
++
++ alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
++
++ yaffs_GrossUnlock(dev);
++
++ if (!alias) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ ret = vfs_follow_link(nd, alias);
++ kfree(alias);
++out:
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++ return ERR_PTR(ret);
++#else
++ return ret;
++#endif
++}
++
++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
++ yaffs_Object *obj);
++
++/*
++ * Lookup is used to find objects in the fs
++ */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
++ struct nameidata *n)
++#else
++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
++#endif
++{
++ yaffs_Object *obj;
++ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
++
++ yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
++
++ yaffs_GrossLock(dev);
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_lookup for %d:%s\n",
++ yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
++
++ obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
++ dentry->d_name.name);
++
++ obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
++
++ /* Can't hold gross lock when calling yaffs_get_inode() */
++ yaffs_GrossUnlock(dev);
++
++ if (obj) {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_lookup found %d\n", obj->objectId));
++
++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++
++ if (inode) {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_loookup dentry \n"));
++/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
++ * d_add even if NULL inode */
++#if 0
++ /*dget(dentry); // try to solve directory bug */
++ d_add(dentry, inode);
++
++ /* return dentry; */
++ return NULL;
++#endif
++ }
++
++ } else {
++ T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n"));
++
++ }
++
++/* added NCB for 2.5/6 compatability - forces add even if inode is
++ * NULL which creates dentry hash */
++ d_add(dentry, inode);
++
++ return NULL;
++}
++
++
++#ifdef YAFFS_HAS_PUT_INODE
++
++/* For now put inode is just for debugging
++ * Put inode is called when the inode **structure** is put.
++ */
++static void yaffs_put_inode(struct inode *inode)
++{
++ T(YAFFS_TRACE_OS,
++ ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
++ atomic_read(&inode->i_count)));
++
++}
++#endif
++
++/* clear is called to tell the fs to release any per-inode data it holds */
++static void yaffs_clear_inode(struct inode *inode)
++{
++ yaffs_Object *obj;
++ yaffs_Device *dev;
++
++ obj = yaffs_InodeToObject(inode);
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
++ atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object"));
++
++ if (obj) {
++ dev = obj->myDev;
++ yaffs_GrossLock(dev);
++
++ /* Clear the association between the inode and
++ * the yaffs_Object.
++ */
++ obj->myInode = NULL;
++ yaffs_InodeToObjectLV(inode) = NULL;
++
++ /* If the object freeing was deferred, then the real
++ * free happens now.
++ * This should fix the inode inconsistency problem.
++ */
++
++ yaffs_HandleDeferedFree(obj);
++
++ yaffs_GrossUnlock(dev);
++ }
++
++}
++
++/* delete is called when the link count is zero and the inode
++ * is put (ie. nobody wants to know about it anymore, time to
++ * delete the file).
++ * NB Must call clear_inode()
++ */
++static void yaffs_delete_inode(struct inode *inode)
++{
++ yaffs_Object *obj = yaffs_InodeToObject(inode);
++ yaffs_Device *dev;
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
++ atomic_read(&inode->i_count),
++ obj ? "object exists" : "null object"));
++
++ if (obj) {
++ dev = obj->myDev;
++ yaffs_GrossLock(dev);
++ yaffs_DeleteObject(obj);
++ yaffs_GrossUnlock(dev);
++ }
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
++ truncate_inode_pages(&inode->i_data, 0);
++#endif
++ clear_inode(inode);
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_file_flush(struct file *file, fl_owner_t id)
++#else
++static int yaffs_file_flush(struct file *file)
++#endif
++{
++ yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
++
++ yaffs_Device *dev = obj->myDev;
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_file_flush object %d (%s)\n", obj->objectId,
++ obj->dirty ? "dirty" : "clean"));
++
++ yaffs_GrossLock(dev);
++
++ yaffs_FlushFile(obj, 1, 0);
++
++ yaffs_GrossUnlock(dev);
++
++ return 0;
++}
++
++static int yaffs_readpage_nolock(struct file *f, struct page *pg)
++{
++ /* Lifted from jffs2 */
++
++ yaffs_Object *obj;
++ unsigned char *pg_buf;
++ int ret;
++
++ yaffs_Device *dev;
++
++ T(YAFFS_TRACE_OS, ("yaffs_readpage_nolock at %08x, size %08x\n",
++ (unsigned)(pg->index << PAGE_CACHE_SHIFT),
++ (unsigned)PAGE_CACHE_SIZE));
++
++ obj = yaffs_DentryToObject(f->f_dentry);
++
++ dev = obj->myDev;
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ BUG_ON(!PageLocked(pg));
++#else
++ if (!PageLocked(pg))
++ PAGE_BUG(pg);
++#endif
++
++ pg_buf = kmap(pg);
++ /* FIXME: Can kmap fail? */
++
++ yaffs_GrossLock(dev);
++
++ ret = yaffs_ReadDataFromFile(obj, pg_buf,
++ pg->index << PAGE_CACHE_SHIFT,
++ PAGE_CACHE_SIZE);
++
++ yaffs_GrossUnlock(dev);
++
++ if (ret >= 0)
++ ret = 0;
++
++ if (ret) {
++ ClearPageUptodate(pg);
++ SetPageError(pg);
++ } else {
++ SetPageUptodate(pg);
++ ClearPageError(pg);
++ }
++
++ flush_dcache_page(pg);
++ kunmap(pg);
++
++ T(YAFFS_TRACE_OS, ("yaffs_readpage_nolock done\n"));
++ return ret;
++}
++
++static int yaffs_readpage_unlock(struct file *f, struct page *pg)
++{
++ int ret = yaffs_readpage_nolock(f, pg);
++ UnlockPage(pg);
++ return ret;
++}
++
++static int yaffs_readpage(struct file *f, struct page *pg)
++{
++ int ret;
++
++ T(YAFFS_TRACE_OS, ("yaffs_readpage\n"));
++ ret=yaffs_readpage_unlock(f, pg);
++ T(YAFFS_TRACE_OS, ("yaffs_readpage done\n"));
++ return ret;
++}
++
++/* writepage inspired by/stolen from smbfs */
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
++#else
++static int yaffs_writepage(struct page *page)
++#endif
++{
++ struct address_space *mapping = page->mapping;
++ struct inode *inode;
++ unsigned long end_index;
++ char *buffer;
++ yaffs_Object *obj;
++ int nWritten = 0;
++ unsigned nBytes;
++ loff_t i_size;
++
++ if (!mapping)
++ BUG();
++ inode = mapping->host;
++ if (!inode)
++ BUG();
++ i_size = i_size_read(inode);
++
++ end_index = i_size >> PAGE_CACHE_SHIFT;
++
++ if(page->index < end_index)
++ nBytes = PAGE_CACHE_SIZE;
++ else {
++ nBytes = i_size & (PAGE_CACHE_SIZE -1);
++
++ if (page->index > end_index || !nBytes) {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_writepage at %08x, inode size = %08x!!!\n",
++ (unsigned)(page->index << PAGE_CACHE_SHIFT),
++ (unsigned)inode->i_size));
++ T(YAFFS_TRACE_OS,
++ (" -> don't care!!\n"));
++
++ zero_user_segment(page,0,PAGE_CACHE_SIZE);
++ set_page_writeback(page);
++ unlock_page(page);
++ end_page_writeback(page);
++ return 0;
++ }
++ }
++
++ if(nBytes != PAGE_CACHE_SIZE)
++ zero_user_segment(page,nBytes,PAGE_CACHE_SIZE);
++
++ get_page(page);
++
++ buffer = kmap(page);
++
++ obj = yaffs_InodeToObject(inode);
++ yaffs_GrossLock(obj->myDev);
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_writepage at %08x, size %08x\n",
++ (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
++ T(YAFFS_TRACE_OS,
++ ("writepag0: obj = %05x, ino = %05x\n",
++ (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
++
++ nWritten = yaffs_WriteDataToFile(obj, buffer,
++ page->index << PAGE_CACHE_SHIFT, nBytes, 0);
++
++ T(YAFFS_TRACE_OS,
++ ("writepag1: obj = %05x, ino = %05x\n",
++ (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
++
++ yaffs_GrossUnlock(obj->myDev);
++
++ kunmap(page);
++ set_page_writeback(page);
++ unlock_page(page);
++ end_page_writeback(page);
++ put_page(page);
++
++ return (nWritten == nBytes) ? 0 : -ENOSPC;
++}
++
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned flags,
++ struct page **pagep, void **fsdata)
++{
++ struct page *pg = NULL;
++ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
++
++ int ret = 0;
++ int space_held = 0;
++
++ /* Get a page */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
++ pg = grab_cache_page_write_begin(mapping, index, flags);
++#else
++ pg = __grab_cache_page(mapping, index);
++#endif
++
++ *pagep = pg;
++ if (!pg) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ T(YAFFS_TRACE_OS, ("start yaffs_write_begin index %d(%x) uptodate %d\n",(int)index,(int)index,Page_Uptodate(pg) ? 1 : 0));
++
++ /* Get fs space */
++ space_held = yaffs_hold_space(filp);
++
++ if (!space_held) {
++ ret = -ENOSPC;
++ goto out;
++ }
++
++ /* Update page if required */
++
++ if (!Page_Uptodate(pg))
++ ret = yaffs_readpage_nolock(filp, pg);
++
++ if (ret)
++ goto out;
++
++ /* Happy path return */
++ T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n"));
++
++ return 0;
++
++out:
++ T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));
++ if (space_held)
++ yaffs_release_space(filp);
++ if (pg) {
++ unlock_page(pg);
++ page_cache_release(pg);
++ }
++ return ret;
++}
++
++#else
++
++static int yaffs_prepare_write(struct file *f, struct page *pg,
++ unsigned offset, unsigned to)
++{
++ T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n"));
++
++ if (!Page_Uptodate(pg))
++ return yaffs_readpage_nolock(f, pg);
++ return 0;
++}
++#endif
++
++#if (YAFFS_USE_WRITE_BEGIN_END > 0)
++static int yaffs_write_end(struct file *filp, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned copied,
++ struct page *pg, void *fsdadata)
++{
++ int ret = 0;
++ void *addr, *kva;
++ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
++
++ kva = kmap(pg);
++ addr = kva + offset_into_page;
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_write_end addr %x pos %x nBytes %d\n",
++ (unsigned) addr,
++ (int)pos, copied));
++
++ ret = yaffs_file_write(filp, addr, copied, &pos);
++
++ if (ret != copied) {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_write_end not same size ret %d copied %d\n",
++ ret, copied));
++ SetPageError(pg);
++ } else {
++ /* Nothing */
++ }
++
++ kunmap(pg);
++
++ yaffs_release_space(filp);
++ unlock_page(pg);
++ page_cache_release(pg);
++ return ret;
++}
++#else
++
++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
++ unsigned to)
++{
++ void *addr, *kva;
++
++ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
++ int nBytes = to - offset;
++ int nWritten;
++
++ unsigned spos = pos;
++ unsigned saddr;
++
++ kva = kmap(pg);
++ addr = kva + offset;
++
++ saddr = (unsigned) addr;
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_commit_write addr %x pos %x nBytes %d\n",
++ saddr, spos, nBytes));
++
++ nWritten = yaffs_file_write(f, addr, nBytes, &pos);
++
++ if (nWritten != nBytes) {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_commit_write not same size nWritten %d nBytes %d\n",
++ nWritten, nBytes));
++ SetPageError(pg);
++ } else {
++ /* Nothing */
++ }
++
++ kunmap(pg);
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_commit_write returning %d\n",
++ nWritten == nBytes ? 0 : nWritten));
++
++ return nWritten == nBytes ? 0 : nWritten;
++}
++#endif
++
++
++static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
++{
++ if (inode && obj) {
++
++
++ /* Check mode against the variant type and attempt to repair if broken. */
++ __u32 mode = obj->yst_mode;
++ switch (obj->variantType) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ if (!S_ISREG(mode)) {
++ obj->yst_mode &= ~S_IFMT;
++ obj->yst_mode |= S_IFREG;
++ }
++
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ if (!S_ISLNK(mode)) {
++ obj->yst_mode &= ~S_IFMT;
++ obj->yst_mode |= S_IFLNK;
++ }
++
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ if (!S_ISDIR(mode)) {
++ obj->yst_mode &= ~S_IFMT;
++ obj->yst_mode |= S_IFDIR;
++ }
++
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ default:
++ /* TODO? */
++ break;
++ }
++
++ inode->i_flags |= S_NOATIME;
++
++ inode->i_ino = obj->objectId;
++ inode->i_mode = obj->yst_mode;
++ inode->i_uid = obj->yst_uid;
++ inode->i_gid = obj->yst_gid;
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++ inode->i_blksize = inode->i_sb->s_blocksize;
++#endif
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++
++ inode->i_rdev = old_decode_dev(obj->yst_rdev);
++ inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
++ inode->i_atime.tv_nsec = 0;
++ inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
++ inode->i_mtime.tv_nsec = 0;
++ inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
++ inode->i_ctime.tv_nsec = 0;
++#else
++ inode->i_rdev = obj->yst_rdev;
++ inode->i_atime = obj->yst_atime;
++ inode->i_mtime = obj->yst_mtime;
++ inode->i_ctime = obj->yst_ctime;
++#endif
++ inode->i_size = yaffs_GetObjectFileLength(obj);
++ inode->i_blocks = (inode->i_size + 511) >> 9;
++
++ inode->i_nlink = yaffs_GetObjectLinkCount(obj);
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
++ inode->i_mode, inode->i_uid, inode->i_gid,
++ (int)inode->i_size, atomic_read(&inode->i_count)));
++
++ switch (obj->yst_mode & S_IFMT) {
++ default: /* fifo, device or socket */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ init_special_inode(inode, obj->yst_mode,
++ old_decode_dev(obj->yst_rdev));
++#else
++ init_special_inode(inode, obj->yst_mode,
++ (dev_t) (obj->yst_rdev));
++#endif
++ break;
++ case S_IFREG: /* file */
++ inode->i_op = &yaffs_file_inode_operations;
++ inode->i_fop = &yaffs_file_operations;
++ inode->i_mapping->a_ops =
++ &yaffs_file_address_operations;
++ break;
++ case S_IFDIR: /* directory */
++ inode->i_op = &yaffs_dir_inode_operations;
++ inode->i_fop = &yaffs_dir_operations;
++ break;
++ case S_IFLNK: /* symlink */
++ inode->i_op = &yaffs_symlink_inode_operations;
++ break;
++ }
++
++ yaffs_InodeToObjectLV(inode) = obj;
++
++ obj->myInode = inode;
++
++ } else {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_FileInode invalid parameters\n"));
++ }
++
++}
++
++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
++ yaffs_Object *obj)
++{
++ struct inode *inode;
++
++ if (!sb) {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_get_inode for NULL super_block!!\n"));
++ return NULL;
++
++ }
++
++ if (!obj) {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_get_inode for NULL object!!\n"));
++ return NULL;
++
++ }
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_get_inode for object %d\n", obj->objectId));
++
++ inode = Y_IGET(sb, obj->objectId);
++ if (IS_ERR(inode))
++ return NULL;
++
++ /* NB Side effect: iget calls back to yaffs_read_inode(). */
++ /* iget also increments the inode's i_count */
++ /* NB You can't be holding grossLock or deadlock will happen! */
++
++ return inode;
++}
++
++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
++ loff_t *pos)
++{
++ yaffs_Object *obj;
++ int nWritten, ipos;
++ struct inode *inode;
++ yaffs_Device *dev;
++
++ obj = yaffs_DentryToObject(f->f_dentry);
++
++ dev = obj->myDev;
++
++ yaffs_GrossLock(dev);
++
++ inode = f->f_dentry->d_inode;
++
++ if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
++ ipos = inode->i_size;
++ else
++ ipos = *pos;
++
++ if (!obj)
++ T(YAFFS_TRACE_OS,
++ ("yaffs_file_write: hey obj is null!\n"));
++ else
++ T(YAFFS_TRACE_OS,
++ ("yaffs_file_write about to write writing %u(%x) bytes"
++ "to object %d at %d(%x)\n",
++ (unsigned) n, (unsigned) n, obj->objectId, ipos,ipos));
++
++ nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_file_write: %d(%x) bytes written\n",
++ (unsigned )n,(unsigned)n));
++
++ if (nWritten > 0) {
++ ipos += nWritten;
++ *pos = ipos;
++ if (ipos > inode->i_size) {
++ inode->i_size = ipos;
++ inode->i_blocks = (ipos + 511) >> 9;
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_file_write size updated to %d bytes, "
++ "%d blocks\n",
++ ipos, (int)(inode->i_blocks)));
++ }
++
++ }
++ yaffs_GrossUnlock(dev);
++ return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
++}
++
++/* Space holding and freeing is done to ensure we have space available for write_begin/end */
++/* For now we just assume few parallel writes and check against a small number. */
++/* Todo: need to do this with a counter to handle parallel reads better */
++
++static ssize_t yaffs_hold_space(struct file *f)
++{
++ yaffs_Object *obj;
++ yaffs_Device *dev;
++
++ int nFreeChunks;
++
++
++ obj = yaffs_DentryToObject(f->f_dentry);
++
++ dev = obj->myDev;
++
++ yaffs_GrossLock(dev);
++
++ nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
++
++ yaffs_GrossUnlock(dev);
++
++ return (nFreeChunks > 20) ? 1 : 0;
++}
++
++static void yaffs_release_space(struct file *f)
++{
++ yaffs_Object *obj;
++ yaffs_Device *dev;
++
++
++ obj = yaffs_DentryToObject(f->f_dentry);
++
++ dev = obj->myDev;
++
++ yaffs_GrossLock(dev);
++
++
++ yaffs_GrossUnlock(dev);
++}
++
++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
++{
++ yaffs_Object *obj;
++ yaffs_Device *dev;
++ struct yaffs_SearchContext *sc;
++ struct inode *inode = f->f_dentry->d_inode;
++ unsigned long offset, curoffs;
++ yaffs_Object *l;
++ int retVal = 0;
++
++ char name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ obj = yaffs_DentryToObject(f->f_dentry);
++ dev = obj->myDev;
++
++ yaffs_GrossLock(dev);
++
++ offset = f->f_pos;
++
++ sc = yaffs_NewSearch(obj);
++ if(!sc){
++ retVal = -ENOMEM;
++ goto unlock_out;
++ }
++
++ T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
++
++ if (offset == 0) {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_readdir: entry . ino %d \n",
++ (int)inode->i_ino));
++ yaffs_GrossUnlock(dev);
++ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
++ goto out;
++ yaffs_GrossLock(dev);
++ offset++;
++ f->f_pos++;
++ }
++ if (offset == 1) {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_readdir: entry .. ino %d \n",
++ (int)f->f_dentry->d_parent->d_inode->i_ino));
++ yaffs_GrossUnlock(dev);
++ if (filldir(dirent, "..", 2, offset,
++ f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
++ goto out;
++ yaffs_GrossLock(dev);
++ offset++;
++ f->f_pos++;
++ }
++
++ curoffs = 1;
++
++ /* If the directory has changed since the open or last call to
++ readdir, rewind to after the 2 canned entries. */
++
++ if (f->f_version != inode->i_version) {
++ offset = 2;
++ f->f_pos = offset;
++ f->f_version = inode->i_version;
++ }
++
++ while(sc->nextReturn){
++ curoffs++;
++ l = sc->nextReturn;
++ if (curoffs >= offset) {
++ int this_inode = yaffs_GetObjectInode(l);
++ int this_type = yaffs_GetObjectType(l);
++
++ yaffs_GetObjectName(l, name,
++ YAFFS_MAX_NAME_LENGTH + 1);
++ T(YAFFS_TRACE_OS,
++ ("yaffs_readdir: %s inode %d\n", name,
++ yaffs_GetObjectInode(l)));
++
++ yaffs_GrossUnlock(dev);
++
++ if (filldir(dirent,
++ name,
++ strlen(name),
++ offset,
++ this_inode,
++ this_type) < 0)
++ goto out;
++
++ yaffs_GrossLock(dev);
++
++ offset++;
++ f->f_pos++;
++ }
++ yaffs_SearchAdvance(sc);
++ }
++
++unlock_out:
++ yaffs_GrossUnlock(dev);
++out:
++ yaffs_EndSearch(sc);
++
++ return retVal;
++}
++
++/*
++ * File creation. Allocate an inode, and we're done..
++ */
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++#define YCRED(x) x
++#else
++#define YCRED(x) (x->cred)
++#endif
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++ dev_t rdev)
++#else
++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++ int rdev)
++#endif
++{
++ struct inode *inode;
++
++ yaffs_Object *obj = NULL;
++ yaffs_Device *dev;
++
++ yaffs_Object *parent = yaffs_InodeToObject(dir);
++
++ int error = -ENOSPC;
++ uid_t uid = YCRED(current)->fsuid;
++ gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
++
++ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
++ mode |= S_ISGID;
++
++ if (parent) {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_mknod: parent object %d type %d\n",
++ parent->objectId, parent->variantType));
++ } else {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_mknod: could not get parent object\n"));
++ return -EPERM;
++ }
++
++ T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
++ "mode %x dev %x\n",
++ dentry->d_name.name, mode, rdev));
++
++ dev = parent->myDev;
++
++ yaffs_GrossLock(dev);
++
++ switch (mode & S_IFMT) {
++ default:
++ /* Special (socket, fifo, device...) */
++ T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n"));
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
++ gid, old_encode_dev(rdev));
++#else
++ obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
++ gid, rdev);
++#endif
++ break;
++ case S_IFREG: /* file */
++ T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n"));
++ obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
++ gid);
++ break;
++ case S_IFDIR: /* directory */
++ T(YAFFS_TRACE_OS,
++ ("yaffs_mknod: making directory\n"));
++ obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
++ uid, gid);
++ break;
++ case S_IFLNK: /* symlink */
++ T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n"));
++ obj = NULL; /* Do we ever get here? */
++ break;
++ }
++
++ /* Can not call yaffs_get_inode() with gross lock held */
++ yaffs_GrossUnlock(dev);
++
++ if (obj) {
++ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
++ d_instantiate(dentry, inode);
++ update_dir_time(dir);
++ T(YAFFS_TRACE_OS,
++ ("yaffs_mknod created object %d count = %d\n",
++ obj->objectId, atomic_read(&inode->i_count)));
++ error = 0;
++ } else {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_mknod failed making object\n"));
++ error = -ENOMEM;
++ }
++
++ return error;
++}
++
++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++ int retVal;
++ T(YAFFS_TRACE_OS, ("yaffs_mkdir\n"));
++ retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
++ return retVal;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
++ struct nameidata *n)
++#else
++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
++#endif
++{
++ T(YAFFS_TRACE_OS, ("yaffs_create\n"));
++ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
++}
++
++static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ int retVal;
++
++ yaffs_Device *dev;
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_unlink %d:%s\n", (int)(dir->i_ino),
++ dentry->d_name.name));
++
++ dev = yaffs_InodeToObject(dir)->myDev;
++
++ yaffs_GrossLock(dev);
++
++ retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
++
++ if (retVal == YAFFS_OK) {
++ dentry->d_inode->i_nlink--;
++ dir->i_version++;
++ yaffs_GrossUnlock(dev);
++ mark_inode_dirty(dentry->d_inode);
++ update_dir_time(dir);
++ return 0;
++ }
++ yaffs_GrossUnlock(dev);
++ return -ENOTEMPTY;
++}
++
++/*
++ * Create a link...
++ */
++static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
++ struct dentry *dentry)
++{
++ struct inode *inode = old_dentry->d_inode;
++ yaffs_Object *obj = NULL;
++ yaffs_Object *link = NULL;
++ yaffs_Device *dev;
++
++ T(YAFFS_TRACE_OS, ("yaffs_link\n"));
++
++ obj = yaffs_InodeToObject(inode);
++ dev = obj->myDev;
++
++ yaffs_GrossLock(dev);
++
++ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
++ link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
++ obj);
++
++ if (link) {
++ old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
++ d_instantiate(dentry, old_dentry->d_inode);
++ atomic_inc(&old_dentry->d_inode->i_count);
++ T(YAFFS_TRACE_OS,
++ ("yaffs_link link count %d i_count %d\n",
++ old_dentry->d_inode->i_nlink,
++ atomic_read(&old_dentry->d_inode->i_count)));
++ }
++
++ yaffs_GrossUnlock(dev);
++
++ if (link){
++ update_dir_time(dir);
++ return 0;
++ }
++
++ return -EPERM;
++}
++
++static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
++ const char *symname)
++{
++ yaffs_Object *obj;
++ yaffs_Device *dev;
++ uid_t uid = YCRED(current)->fsuid;
++ gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
++
++ T(YAFFS_TRACE_OS, ("yaffs_symlink\n"));
++
++ dev = yaffs_InodeToObject(dir)->myDev;
++ yaffs_GrossLock(dev);
++ obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
++ S_IFLNK | S_IRWXUGO, uid, gid, symname);
++ yaffs_GrossUnlock(dev);
++
++ if (obj) {
++ struct inode *inode;
++
++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
++ d_instantiate(dentry, inode);
++ update_dir_time(dir);
++ T(YAFFS_TRACE_OS, ("symlink created OK\n"));
++ return 0;
++ } else {
++ T(YAFFS_TRACE_OS, ("symlink not created\n"));
++ }
++
++ return -ENOMEM;
++}
++
++static int yaffs_sync_object(struct file *file, struct dentry *dentry,
++ int datasync)
++{
++
++ yaffs_Object *obj;
++ yaffs_Device *dev;
++
++ obj = yaffs_DentryToObject(dentry);
++
++ dev = obj->myDev;
++
++ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ("yaffs_sync_object\n"));
++ yaffs_GrossLock(dev);
++ yaffs_FlushFile(obj, 1, datasync);
++ yaffs_GrossUnlock(dev);
++ return 0;
++}
++
++/*
++ * The VFS layer already does all the dentry stuff for rename.
++ *
++ * NB: POSIX says you can rename an object over an old object of the same name
++ */
++static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
++ struct inode *new_dir, struct dentry *new_dentry)
++{
++ yaffs_Device *dev;
++ int retVal = YAFFS_FAIL;
++ yaffs_Object *target;
++
++ T(YAFFS_TRACE_OS, ("yaffs_rename\n"));
++ dev = yaffs_InodeToObject(old_dir)->myDev;
++
++ yaffs_GrossLock(dev);
++
++ /* Check if the target is an existing directory that is not empty. */
++ target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
++ new_dentry->d_name.name);
++
++
++
++ if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
++ !ylist_empty(&target->variant.directoryVariant.children)) {
++
++ T(YAFFS_TRACE_OS, ("target is non-empty dir\n"));
++
++ retVal = YAFFS_FAIL;
++ } else {
++ /* Now does unlinking internally using shadowing mechanism */
++ T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n"));
++
++ retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
++ old_dentry->d_name.name,
++ yaffs_InodeToObject(new_dir),
++ new_dentry->d_name.name);
++ }
++ yaffs_GrossUnlock(dev);
++
++ if (retVal == YAFFS_OK) {
++ if (target) {
++ new_dentry->d_inode->i_nlink--;
++ mark_inode_dirty(new_dentry->d_inode);
++ }
++
++ update_dir_time(old_dir);
++ if(old_dir != new_dir)
++ update_dir_time(new_dir);
++ return 0;
++ } else {
++ return -ENOTEMPTY;
++ }
++}
++
++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
++{
++ struct inode *inode = dentry->d_inode;
++ int error;
++ yaffs_Device *dev;
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_setattr of object %d\n",
++ yaffs_InodeToObject(inode)->objectId));
++
++ error = inode_change_ok(inode, attr);
++ if (error == 0) {
++ int result;
++ if (!error){
++ error = inode_setattr(inode, attr);
++ T(YAFFS_TRACE_OS,("inode_setattr called\n"));
++ if (attr->ia_valid & ATTR_SIZE)
++ truncate_inode_pages(&inode->i_data,attr->ia_size);
++ }
++ dev = yaffs_InodeToObject(inode)->myDev;
++ if (attr->ia_valid & ATTR_SIZE){
++ T(YAFFS_TRACE_OS,("resize to %d(%x)\n",(int)(attr->ia_size),(int)(attr->ia_size)));
++ }
++ yaffs_GrossLock(dev);
++ result = yaffs_SetAttributes(yaffs_InodeToObject(inode), attr);
++ if(result == YAFFS_OK) {
++ error = 0;
++ } else {
++ error = -EPERM;
++ }
++ yaffs_GrossUnlock(dev);
++
++ }
++ T(YAFFS_TRACE_OS,
++ ("yaffs_setattr done\n"));
++
++ return error;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
++ struct super_block *sb = dentry->d_sb;
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
++{
++ yaffs_Device *dev = yaffs_SuperToDevice(sb);
++#else
++static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
++{
++ yaffs_Device *dev = yaffs_SuperToDevice(sb);
++#endif
++
++ T(YAFFS_TRACE_OS, ("yaffs_statfs\n"));
++
++ yaffs_GrossLock(dev);
++
++ buf->f_type = YAFFS_MAGIC;
++ buf->f_bsize = sb->s_blocksize;
++ buf->f_namelen = 255;
++
++ if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
++ /* Do this if chunk size is not a power of 2 */
++
++ uint64_t bytesInDev;
++ uint64_t bytesFree;
++
++ bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) *
++ ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
++
++ do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
++ buf->f_blocks = bytesInDev;
++
++ bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
++ ((uint64_t)(dev->nDataBytesPerChunk));
++
++ do_div(bytesFree, sb->s_blocksize);
++
++ buf->f_bfree = bytesFree;
++
++ } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
++
++ buf->f_blocks =
++ (dev->endBlock - dev->startBlock + 1) *
++ dev->nChunksPerBlock /
++ (sb->s_blocksize / dev->nDataBytesPerChunk);
++ buf->f_bfree =
++ yaffs_GetNumberOfFreeChunks(dev) /
++ (sb->s_blocksize / dev->nDataBytesPerChunk);
++ } else {
++ buf->f_blocks =
++ (dev->endBlock - dev->startBlock + 1) *
++ dev->nChunksPerBlock *
++ (dev->nDataBytesPerChunk / sb->s_blocksize);
++
++ buf->f_bfree =
++ yaffs_GetNumberOfFreeChunks(dev) *
++ (dev->nDataBytesPerChunk / sb->s_blocksize);
++ }
++
++ buf->f_files = 0;
++ buf->f_ffree = 0;
++ buf->f_bavail = buf->f_bfree;
++
++ yaffs_GrossUnlock(dev);
++ return 0;
++}
++
++
++
++static void yaffs_flush_sb_inodes(struct super_block *sb)
++{
++ struct inode *iptr;
++ yaffs_Object *obj;
++
++ list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
++ obj = yaffs_InodeToObject(iptr);
++ if(obj){
++ T(YAFFS_TRACE_OS, ("flushing obj %d\n",obj->objectId));
++ yaffs_FlushFile(obj,1,0);
++ }
++ }
++}
++
++static int yaffs_do_sync_fs(struct super_block *sb)
++{
++
++ yaffs_Device *dev = yaffs_SuperToDevice(sb);
++ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ("yaffs_do_sync_fs\n"));
++
++ if (sb->s_dirt) {
++ yaffs_GrossLock(dev);
++
++ if (dev) {
++ yaffs_FlushEntireDeviceCache(dev);
++ yaffs_flush_sb_inodes(sb);
++ yaffs_CheckpointSave(dev);
++ }
++
++ yaffs_GrossUnlock(dev);
++
++ sb->s_dirt = 0;
++ }
++ return 0;
++}
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static void yaffs_write_super(struct super_block *sb)
++#else
++static int yaffs_write_super(struct super_block *sb)
++#endif
++{
++
++ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ("yaffs_write_super\n"));
++ if (yaffs_auto_checkpoint >= 2)
++ yaffs_do_sync_fs(sb);
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
++ return 0;
++#endif
++}
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_sync_fs(struct super_block *sb, int wait)
++#else
++static int yaffs_sync_fs(struct super_block *sb)
++#endif
++{
++ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ("yaffs_sync_fs\n"));
++
++ if (yaffs_auto_checkpoint >= 1)
++ yaffs_do_sync_fs(sb);
++
++ return 0;
++}
++
++#ifdef YAFFS_USE_OWN_IGET
++
++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
++{
++ struct inode *inode;
++ yaffs_Object *obj;
++ yaffs_Device *dev = yaffs_SuperToDevice(sb);
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_iget for %lu\n", ino));
++
++ inode = iget_locked(sb, ino);
++ if (!inode)
++ return ERR_PTR(-ENOMEM);
++ if (!(inode->i_state & I_NEW))
++ return inode;
++
++ /* NB This is called as a side effect of other functions, but
++ * we had to release the lock to prevent deadlocks, so
++ * need to lock again.
++ */
++
++ yaffs_GrossLock(dev);
++
++ obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
++
++ yaffs_FillInodeFromObject(inode, obj);
++
++ yaffs_GrossUnlock(dev);
++
++ unlock_new_inode(inode);
++ return inode;
++}
++
++#else
++
++static void yaffs_read_inode(struct inode *inode)
++{
++ /* NB This is called as a side effect of other functions, but
++ * we had to release the lock to prevent deadlocks, so
++ * need to lock again.
++ */
++
++ yaffs_Object *obj;
++ yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_read_inode for %d\n", (int)inode->i_ino));
++
++ yaffs_GrossLock(dev);
++
++ obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
++
++ yaffs_FillInodeFromObject(inode, obj);
++
++ yaffs_GrossUnlock(dev);
++}
++
++#endif
++
++static YLIST_HEAD(yaffs_dev_list);
++
++#if 0 /* not used */
++static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
++{
++ yaffs_Device *dev = yaffs_SuperToDevice(sb);
++
++ if (*flags & MS_RDONLY) {
++ struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_remount_fs: %s: RO\n", dev->name));
++
++ yaffs_GrossLock(dev);
++
++ yaffs_FlushEntireDeviceCache(dev);
++
++ yaffs_CheckpointSave(dev);
++
++ if (mtd->sync)
++ mtd->sync(mtd);
++
++ yaffs_GrossUnlock(dev);
++ } else {
++ T(YAFFS_TRACE_OS,
++ ("yaffs_remount_fs: %s: RW\n", dev->name));
++ }
++
++ return 0;
++}
++#endif
++
++static void yaffs_put_super(struct super_block *sb)
++{
++ yaffs_Device *dev = yaffs_SuperToDevice(sb);
++
++ T(YAFFS_TRACE_OS, ("yaffs_put_super\n"));
++
++ yaffs_GrossLock(dev);
++
++ yaffs_FlushEntireDeviceCache(dev);
++
++ yaffs_CheckpointSave(dev);
++
++ if (dev->putSuperFunc)
++ dev->putSuperFunc(sb);
++
++ yaffs_Deinitialise(dev);
++
++ yaffs_GrossUnlock(dev);
++
++ /* we assume this is protected by lock_kernel() in mount/umount */
++ ylist_del(&dev->devList);
++
++ if (dev->spareBuffer) {
++ YFREE(dev->spareBuffer);
++ dev->spareBuffer = NULL;
++ }
++
++ kfree(dev);
++}
++
++
++static void yaffs_MTDPutSuper(struct super_block *sb)
++{
++ struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
++
++ if (mtd->sync)
++ mtd->sync(mtd);
++
++ put_mtd_device(mtd);
++}
++
++
++static void yaffs_MarkSuperBlockDirty(void *vsb)
++{
++ struct super_block *sb = (struct super_block *)vsb;
++
++ T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb));
++ if (sb)
++ sb->s_dirt = 1;
++}
++
++typedef struct {
++ int inband_tags;
++ int skip_checkpoint_read;
++ int skip_checkpoint_write;
++ int no_cache;
++ int tags_ecc_on;
++ int tags_ecc_overridden;
++ int lazy_loading_enabled;
++ int lazy_loading_overridden;
++ int empty_lost_and_found;
++ int empty_lost_and_found_overridden;
++} yaffs_options;
++
++#define MAX_OPT_LEN 30
++static int yaffs_parse_options(yaffs_options *options, const char *options_str)
++{
++ char cur_opt[MAX_OPT_LEN + 1];
++ int p;
++ int error = 0;
++
++ /* Parse through the options which is a comma seperated list */
++
++ while (options_str && *options_str && !error) {
++ memset(cur_opt, 0, MAX_OPT_LEN + 1);
++ p = 0;
++
++ while(*options_str == ',')
++ options_str++;
++
++ while (*options_str && *options_str != ',') {
++ if (p < MAX_OPT_LEN) {
++ cur_opt[p] = *options_str;
++ p++;
++ }
++ options_str++;
++ }
++
++ if (!strcmp(cur_opt, "inband-tags"))
++ options->inband_tags = 1;
++ else if (!strcmp(cur_opt, "tags-ecc-off")){
++ options->tags_ecc_on = 0;
++ options->tags_ecc_overridden=1;
++ } else if (!strcmp(cur_opt, "tags-ecc-on")){
++ options->tags_ecc_on = 1;
++ options->tags_ecc_overridden = 1;
++ } else if (!strcmp(cur_opt, "lazy-loading-off")){
++ options->lazy_loading_enabled = 0;
++ options->lazy_loading_overridden=1;
++ } else if (!strcmp(cur_opt, "lazy-loading-on")){
++ options->lazy_loading_enabled = 1;
++ options->lazy_loading_overridden = 1;
++ } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
++ options->empty_lost_and_found = 0;
++ options->empty_lost_and_found_overridden=1;
++ } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
++ options->empty_lost_and_found = 1;
++ options->empty_lost_and_found_overridden=1;
++ } else if (!strcmp(cur_opt, "no-cache"))
++ options->no_cache = 1;
++ else if (!strcmp(cur_opt, "no-checkpoint-read"))
++ options->skip_checkpoint_read = 1;
++ else if (!strcmp(cur_opt, "no-checkpoint-write"))
++ options->skip_checkpoint_write = 1;
++ else if (!strcmp(cur_opt, "no-checkpoint")) {
++ options->skip_checkpoint_read = 1;
++ options->skip_checkpoint_write = 1;
++ } else {
++ printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
++ cur_opt);
++ error = 1;
++ }
++ }
++
++ return error;
++}
++
++static struct super_block *yaffs_internal_read_super(int yaffsVersion,
++ struct super_block *sb,
++ void *data, int silent)
++{
++ int nBlocks;
++ struct inode *inode = NULL;
++ struct dentry *root;
++ yaffs_Device *dev = 0;
++ char devname_buf[BDEVNAME_SIZE + 1];
++ struct mtd_info *mtd;
++ int err;
++ char *data_str = (char *)data;
++
++ yaffs_options options;
++
++ sb->s_magic = YAFFS_MAGIC;
++ sb->s_op = &yaffs_super_ops;
++ sb->s_flags |= MS_NOATIME;
++
++ if (!sb)
++ printk(KERN_INFO "yaffs: sb is NULL\n");
++ else if (!sb->s_dev)
++ printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
++ else if (!yaffs_devname(sb, devname_buf))
++ printk(KERN_INFO "yaffs: devname is NULL\n");
++ else
++ printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
++ sb->s_dev,
++ yaffs_devname(sb, devname_buf));
++
++ if (!data_str)
++ data_str = "";
++
++ printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
++
++ memset(&options, 0, sizeof(options));
++
++ if (yaffs_parse_options(&options, data_str)) {
++ /* Option parsing failed */
++ return NULL;
++ }
++
++
++ sb->s_blocksize = PAGE_CACHE_SIZE;
++ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
++ T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
++ T(YAFFS_TRACE_OS,
++ ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
++
++#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
++ T(YAFFS_TRACE_OS,
++ ("yaffs: Write verification disabled. All guarantees "
++ "null and void\n"));
++#endif
++
++ T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
++ "\"%s\"\n",
++ MAJOR(sb->s_dev), MINOR(sb->s_dev),
++ yaffs_devname(sb, devname_buf)));
++
++ /* Check it's an mtd device..... */
++ if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
++ return NULL; /* This isn't an mtd device */
++
++ /* Get the device */
++ mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
++ if (!mtd) {
++ T(YAFFS_TRACE_ALWAYS,
++ ("yaffs: MTD device #%u doesn't appear to exist\n",
++ MINOR(sb->s_dev)));
++ return NULL;
++ }
++ /* Check it's NAND */
++ if (mtd->type != MTD_NANDFLASH) {
++ T(YAFFS_TRACE_ALWAYS,
++ ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
++ return NULL;
++ }
++
++ T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
++ T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
++ T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
++ T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
++ T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
++ T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
++ T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
++ T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
++ T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
++ T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++ T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));
++#else
++ T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
++#endif
++
++#ifdef CONFIG_YAFFS_AUTO_YAFFS2
++
++ if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
++ T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
++ yaffsVersion = 2;
++ }
++
++ /* Added NCB 26/5/2006 for completeness */
++ if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
++ T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
++ yaffsVersion = 1;
++ }
++
++#endif
++
++ if (yaffsVersion == 2) {
++ /* Check for version 2 style functions */
++ if (!mtd->erase ||
++ !mtd->block_isbad ||
++ !mtd->block_markbad ||
++ !mtd->read ||
++ !mtd->write ||
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ !mtd->read_oob || !mtd->write_oob) {
++#else
++ !mtd->write_ecc ||
++ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
++#endif
++ T(YAFFS_TRACE_ALWAYS,
++ ("yaffs: MTD device does not support required "
++ "functions\n"));;
++ return NULL;
++ }
++
++ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
++ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
++ !options.inband_tags) {
++ T(YAFFS_TRACE_ALWAYS,
++ ("yaffs: MTD device does not have the "
++ "right page sizes\n"));
++ return NULL;
++ }
++ } else {
++ /* Check for V1 style functions */
++ if (!mtd->erase ||
++ !mtd->read ||
++ !mtd->write ||
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ !mtd->read_oob || !mtd->write_oob) {
++#else
++ !mtd->write_ecc ||
++ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
++#endif
++ T(YAFFS_TRACE_ALWAYS,
++ ("yaffs: MTD device does not support required "
++ "functions\n"));;
++ return NULL;
++ }
++
++ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
++ mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
++ T(YAFFS_TRACE_ALWAYS,
++ ("yaffs: MTD device does not support have the "
++ "right page sizes\n"));
++ return NULL;
++ }
++ }
++
++ /* OK, so if we got here, we have an MTD that's NAND and looks
++ * like it has the right capabilities
++ * Set the yaffs_Device up for mtd
++ */
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++ sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
++#else
++ sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
++#endif
++ if (!dev) {
++ /* Deep shit could not allocate device structure */
++ T(YAFFS_TRACE_ALWAYS,
++ ("yaffs_read_super: Failed trying to allocate "
++ "yaffs_Device. \n"));
++ return NULL;
++ }
++
++ memset(dev, 0, sizeof(yaffs_Device));
++ dev->genericDevice = mtd;
++ dev->name = mtd->name;
++
++ /* Set up the memory size parameters.... */
++
++ nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
++
++ dev->startBlock = 0;
++ dev->endBlock = nBlocks - 1;
++ dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
++ dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
++ dev->nReservedBlocks = 5;
++ dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
++ dev->inbandTags = options.inband_tags;
++
++#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
++ dev->disableLazyLoad = 1;
++#endif
++ if(options.lazy_loading_overridden)
++ dev->disableLazyLoad = !options.lazy_loading_enabled;
++
++#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
++ dev->noTagsECC = 1;
++#endif
++ if(options.tags_ecc_overridden)
++ dev->noTagsECC = !options.tags_ecc_on;
++
++#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
++ dev->emptyLostAndFound = 1;
++#endif
++ if(options.empty_lost_and_found_overridden)
++ dev->emptyLostAndFound = options.empty_lost_and_found;
++
++ /* ... and the functions. */
++ if (yaffsVersion == 2) {
++ dev->writeChunkWithTagsToNAND =
++ nandmtd2_WriteChunkWithTagsToNAND;
++ dev->readChunkWithTagsFromNAND =
++ nandmtd2_ReadChunkWithTagsFromNAND;
++ dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
++ dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
++ dev->spareBuffer = YMALLOC(mtd->oobsize);
++ dev->isYaffs2 = 1;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ dev->totalBytesPerChunk = mtd->writesize;
++ dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
++#else
++ dev->totalBytesPerChunk = mtd->oobblock;
++ dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
++#endif
++ nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
++
++ dev->startBlock = 0;
++ dev->endBlock = nBlocks - 1;
++ } else {
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ /* use the MTD interface in yaffs_mtdif1.c */
++ dev->writeChunkWithTagsToNAND =
++ nandmtd1_WriteChunkWithTagsToNAND;
++ dev->readChunkWithTagsFromNAND =
++ nandmtd1_ReadChunkWithTagsFromNAND;
++ dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
++ dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
++#else
++ dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
++ dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
++#endif
++ dev->isYaffs2 = 0;
++ }
++ /* ... and common functions */
++ dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
++ dev->initialiseNAND = nandmtd_InitialiseNAND;
++
++ dev->putSuperFunc = yaffs_MTDPutSuper;
++
++ dev->superBlock = (void *)sb;
++ dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
++
++
++#ifndef CONFIG_YAFFS_DOES_ECC
++ dev->useNANDECC = 1;
++#endif
++
++#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
++ dev->wideTnodesDisabled = 1;
++#endif
++
++ dev->skipCheckpointRead = options.skip_checkpoint_read;
++ dev->skipCheckpointWrite = options.skip_checkpoint_write;
++
++ /* we assume this is protected by lock_kernel() in mount/umount */
++ ylist_add_tail(&dev->devList, &yaffs_dev_list);
++
++ /* Directory search handling...*/
++ YINIT_LIST_HEAD(&dev->searchContexts);
++ dev->removeObjectCallback = yaffs_RemoveObjectCallback;
++
++ init_MUTEX(&dev->grossLock);
++
++ yaffs_GrossLock(dev);
++
++ err = yaffs_GutsInitialise(dev);
++
++ T(YAFFS_TRACE_OS,
++ ("yaffs_read_super: guts initialised %s\n",
++ (err == YAFFS_OK) ? "OK" : "FAILED"));
++
++ /* Release lock before yaffs_get_inode() */
++ yaffs_GrossUnlock(dev);
++
++ /* Create root inode */
++ if (err == YAFFS_OK)
++ inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
++ yaffs_Root(dev));
++
++ if (!inode)
++ return NULL;
++
++ inode->i_op = &yaffs_dir_inode_operations;
++ inode->i_fop = &yaffs_dir_operations;
++
++ T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
++
++ root = d_alloc_root(inode);
++
++ T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
++
++ if (!root) {
++ iput(inode);
++ return NULL;
++ }
++ sb->s_root = root;
++ sb->s_dirt = !dev->isCheckpointed;
++ T(YAFFS_TRACE_ALWAYS,
++ ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));
++
++ T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
++ return sb;
++}
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
++ int silent)
++{
++ return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs_read_super(struct file_system_type *fs,
++ int flags, const char *dev_name,
++ void *data, struct vfsmount *mnt)
++{
++
++ return get_sb_bdev(fs, flags, dev_name, data,
++ yaffs_internal_read_super_mtd, mnt);
++}
++#else
++static struct super_block *yaffs_read_super(struct file_system_type *fs,
++ int flags, const char *dev_name,
++ void *data)
++{
++
++ return get_sb_bdev(fs, flags, dev_name, data,
++ yaffs_internal_read_super_mtd);
++}
++#endif
++
++static struct file_system_type yaffs_fs_type = {
++ .owner = THIS_MODULE,
++ .name = "yaffs",
++ .get_sb = yaffs_read_super,
++ .kill_sb = kill_block_super,
++ .fs_flags = FS_REQUIRES_DEV,
++};
++#else
++static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
++ int silent)
++{
++ return yaffs_internal_read_super(1, sb, data, silent);
++}
++
++static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
++ FS_REQUIRES_DEV);
++#endif
++
++
++#ifdef CONFIG_YAFFS_YAFFS2
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
++ int silent)
++{
++ return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++static int yaffs2_read_super(struct file_system_type *fs,
++ int flags, const char *dev_name, void *data,
++ struct vfsmount *mnt)
++{
++ return get_sb_bdev(fs, flags, dev_name, data,
++ yaffs2_internal_read_super_mtd, mnt);
++}
++#else
++static struct super_block *yaffs2_read_super(struct file_system_type *fs,
++ int flags, const char *dev_name,
++ void *data)
++{
++
++ return get_sb_bdev(fs, flags, dev_name, data,
++ yaffs2_internal_read_super_mtd);
++}
++#endif
++
++static struct file_system_type yaffs2_fs_type = {
++ .owner = THIS_MODULE,
++ .name = "yaffs2",
++ .get_sb = yaffs2_read_super,
++ .kill_sb = kill_block_super,
++ .fs_flags = FS_REQUIRES_DEV,
++};
++#else
++static struct super_block *yaffs2_read_super(struct super_block *sb,
++ void *data, int silent)
++{
++ return yaffs_internal_read_super(2, sb, data, silent);
++}
++
++static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
++ FS_REQUIRES_DEV);
++#endif
++
++#endif /* CONFIG_YAFFS_YAFFS2 */
++
++static struct proc_dir_entry *my_proc_entry;
++
++static char *yaffs_dump_dev_part0(char *buf, yaffs_Device * dev)
++{
++ buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
++ buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
++ buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
++ buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
++ buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
++ buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
++ buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
++ buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
++ buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
++ buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
++ buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
++ buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
++ buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
++ buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
++ buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
++ buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
++ buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
++ buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
++ buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
++ buf += sprintf(buf, "passiveGCs......... %d\n",
++ dev->passiveGarbageCollections);
++ buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
++ buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
++ buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
++ buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
++ buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
++ buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
++ buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
++ buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
++ buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
++ buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
++ buf +=
++ sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
++
++ return buf;
++}
++
++
++static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
++{
++ buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
++ buf += sprintf(buf, "noTagsECC.......... %d\n", dev->noTagsECC);
++ buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
++ buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
++ buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->emptyLostAndFound);
++ buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->disableLazyLoad);
++
++ return buf;
++}
++
++static int yaffs_proc_read(char *page,
++ char **start,
++ off_t offset, int count, int *eof, void *data)
++{
++ struct ylist_head *item;
++ char *buf = page;
++ int step = offset;
++ int n = 0;
++
++ /* Get proc_file_read() to step 'offset' by one on each sucessive call.
++ * We use 'offset' (*ppos) to indicate where we are in devList.
++ * This also assumes the user has posted a read buffer large
++ * enough to hold the complete output; but that's life in /proc.
++ */
++
++ *(int *)start = 1;
++
++ /* Print header first */
++ if (step == 0)
++ buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
++ "\n%s\n%s\n", yaffs_fs_c_version,
++ yaffs_guts_c_version);
++ else if (step == 1)
++ buf += sprintf(buf,"\n");
++ else {
++ step-=2;
++
++ /* hold lock_kernel while traversing yaffs_dev_list */
++ lock_kernel();
++
++ /* Locate and print the Nth entry. Order N-squared but N is small. */
++ ylist_for_each(item, &yaffs_dev_list) {
++ yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
++ if (n < (step & ~1)) {
++ n+=2;
++ continue;
++ }
++ if((step & 1)==0){
++ buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
++ buf = yaffs_dump_dev_part0(buf, dev);
++ } else
++ buf = yaffs_dump_dev_part1(buf, dev);
++
++ break;
++ }
++ unlock_kernel();
++ }
++
++ return buf - page < count ? buf - page : count;
++}
++
++/**
++ * Set the verbosity of the warnings and error messages.
++ *
++ * Note that the names can only be a..z or _ with the current code.
++ */
++
++static struct {
++ char *mask_name;
++ unsigned mask_bitfield;
++} mask_flags[] = {
++ {"allocate", YAFFS_TRACE_ALLOCATE},
++ {"always", YAFFS_TRACE_ALWAYS},
++ {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
++ {"buffers", YAFFS_TRACE_BUFFERS},
++ {"bug", YAFFS_TRACE_BUG},
++ {"checkpt", YAFFS_TRACE_CHECKPOINT},
++ {"deletion", YAFFS_TRACE_DELETION},
++ {"erase", YAFFS_TRACE_ERASE},
++ {"error", YAFFS_TRACE_ERROR},
++ {"gc_detail", YAFFS_TRACE_GC_DETAIL},
++ {"gc", YAFFS_TRACE_GC},
++ {"mtd", YAFFS_TRACE_MTD},
++ {"nandaccess", YAFFS_TRACE_NANDACCESS},
++ {"os", YAFFS_TRACE_OS},
++ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
++ {"scan", YAFFS_TRACE_SCAN},
++ {"tracing", YAFFS_TRACE_TRACING},
++ {"sync", YAFFS_TRACE_SYNC},
++
++ {"verify", YAFFS_TRACE_VERIFY},
++ {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
++ {"verify_full", YAFFS_TRACE_VERIFY_FULL},
++ {"verify_all", YAFFS_TRACE_VERIFY_ALL},
++
++ {"write", YAFFS_TRACE_WRITE},
++ {"all", 0xffffffff},
++ {"none", 0},
++ {NULL, 0},
++};
++
++#define MAX_MASK_NAME_LENGTH 40
++static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
++ unsigned long count, void *data)
++{
++ unsigned rg = 0, mask_bitfield;
++ char *end;
++ char *mask_name;
++ const char *x;
++ char substring[MAX_MASK_NAME_LENGTH + 1];
++ int i;
++ int done = 0;
++ int add, len = 0;
++ int pos = 0;
++
++ rg = yaffs_traceMask;
++
++ while (!done && (pos < count)) {
++ done = 1;
++ while ((pos < count) && isspace(buf[pos]))
++ pos++;
++
++ switch (buf[pos]) {
++ case '+':
++ case '-':
++ case '=':
++ add = buf[pos];
++ pos++;
++ break;
++
++ default:
++ add = ' ';
++ break;
++ }
++ mask_name = NULL;
++
++ mask_bitfield = simple_strtoul(buf + pos, &end, 0);
++
++ if (end > buf + pos) {
++ mask_name = "numeral";
++ len = end - (buf + pos);
++ pos += len;
++ done = 0;
++ } else {
++ for (x = buf + pos, i = 0;
++ (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
++ i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
++ substring[i] = *x;
++ substring[i] = '\0';
++
++ for (i = 0; mask_flags[i].mask_name != NULL; i++) {
++ if (strcmp(substring, mask_flags[i].mask_name) == 0) {
++ mask_name = mask_flags[i].mask_name;
++ mask_bitfield = mask_flags[i].mask_bitfield;
++ done = 0;
++ break;
++ }
++ }
++ }
++
++ if (mask_name != NULL) {
++ done = 0;
++ switch (add) {
++ case '-':
++ rg &= ~mask_bitfield;
++ break;
++ case '+':
++ rg |= mask_bitfield;
++ break;
++ case '=':
++ rg = mask_bitfield;
++ break;
++ default:
++ rg |= mask_bitfield;
++ break;
++ }
++ }
++ }
++
++ yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
++
++ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
++
++ if (rg & YAFFS_TRACE_ALWAYS) {
++ for (i = 0; mask_flags[i].mask_name != NULL; i++) {
++ char flag;
++ flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
++ printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
++ }
++ }
++
++ return count;
++}
++
++
++static int yaffs_proc_write(struct file *file, const char *buf,
++ unsigned long count, void *data)
++{
++ return yaffs_proc_write_trace_options(file, buf, count, data);
++}
++
++/* Stuff to handle installation of file systems */
++struct file_system_to_install {
++ struct file_system_type *fst;
++ int installed;
++};
++
++static struct file_system_to_install fs_to_install[] = {
++ {&yaffs_fs_type, 0},
++ {&yaffs2_fs_type, 0},
++ {NULL, 0}
++};
++
++static int __init init_yaffs_fs(void)
++{
++ int error = 0;
++ struct file_system_to_install *fsinst;
++
++ T(YAFFS_TRACE_ALWAYS,
++ ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
++
++ /* Install the proc_fs entry */
++ my_proc_entry = create_proc_entry("yaffs",
++ S_IRUGO | S_IFREG,
++ YPROC_ROOT);
++
++ if (my_proc_entry) {
++ my_proc_entry->write_proc = yaffs_proc_write;
++ my_proc_entry->read_proc = yaffs_proc_read;
++ my_proc_entry->data = NULL;
++ } else
++ return -ENOMEM;
++
++ /* Now add the file system entries */
++
++ fsinst = fs_to_install;
++
++ while (fsinst->fst && !error) {
++ error = register_filesystem(fsinst->fst);
++ if (!error)
++ fsinst->installed = 1;
++ fsinst++;
++ }
++
++ /* Any errors? uninstall */
++ if (error) {
++ fsinst = fs_to_install;
++
++ while (fsinst->fst) {
++ if (fsinst->installed) {
++ unregister_filesystem(fsinst->fst);
++ fsinst->installed = 0;
++ }
++ fsinst++;
++ }
++ }
++
++ return error;
++}
++
++static void __exit exit_yaffs_fs(void)
++{
++
++ struct file_system_to_install *fsinst;
++
++ T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
++ " removing. \n"));
++
++ remove_proc_entry("yaffs", YPROC_ROOT);
++
++ fsinst = fs_to_install;
++
++ while (fsinst->fst) {
++ if (fsinst->installed) {
++ unregister_filesystem(fsinst->fst);
++ fsinst->installed = 0;
++ }
++ fsinst++;
++ }
++}
++
++module_init(init_yaffs_fs)
++module_exit(exit_yaffs_fs)
++
++MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
++MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_getblockinfo.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_getblockinfo.h
+--- linux-2.6.29/fs/yaffs2/yaffs_getblockinfo.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_getblockinfo.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,35 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GETBLOCKINFO_H__
++#define __YAFFS_GETBLOCKINFO_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++
++/* Function to manipulate block info */
++static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
++{
++ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
++ blk));
++ YBUG();
++ }
++ return &dev->blockInfo[blk - dev->internalStartBlock];
++}
++
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_guts.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_guts.c
+--- linux-2.6.29/fs/yaffs2/yaffs_guts.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_guts.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,7850 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++const char *yaffs_guts_c_version =
++ "$Id: yaffs_guts.c,v 1.106 2010-01-11 04:06:46 charles Exp $";
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++#include "yaffsinterface.h"
++#include "yaffs_guts.h"
++#include "yaffs_tagsvalidity.h"
++#include "yaffs_getblockinfo.h"
++
++#include "yaffs_tagscompat.h"
++#ifndef CONFIG_YAFFS_USE_OWN_SORT
++#include "yaffs_qsort.h"
++#endif
++#include "yaffs_nand.h"
++
++#include "yaffs_checkptrw.h"
++
++#include "yaffs_nand.h"
++#include "yaffs_packedtags2.h"
++
++
++#define YAFFS_PASSIVE_GC_CHUNKS 2
++
++#include "yaffs_ecc.h"
++
++
++/* Robustification (if it ever comes about...) */
++static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);
++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
++ int erasedOk);
++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
++ const __u8 *data,
++ const yaffs_ExtendedTags *tags);
++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
++ const yaffs_ExtendedTags *tags);
++
++/* Other local prototypes */
++static void yaffs_UpdateParent(yaffs_Object *obj);
++static int yaffs_UnlinkObject(yaffs_Object *obj);
++static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
++
++static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
++
++static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev,
++ const __u8 *buffer,
++ yaffs_ExtendedTags *tags,
++ int useReserve);
++static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
++ int chunkInNAND, int inScan);
++
++static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
++ yaffs_ObjectType type);
++static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
++ yaffs_Object *obj);
++static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
++ int force, int isShrink, int shadows);
++static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
++static int yaffs_CheckStructures(void);
++static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
++ int chunkOffset, int *limit);
++static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
++
++static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
++
++
++static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
++ int chunkInNAND);
++
++static int yaffs_UnlinkWorker(yaffs_Object *obj);
++
++static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
++ int chunkInObject);
++
++static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
++ yaffs_BlockInfo **blockUsedPtr);
++
++static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
++
++static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
++
++static void yaffs_VerifyDirectory(yaffs_Object *directory);
++#ifdef YAFFS_PARANOID
++static int yaffs_CheckFileSanity(yaffs_Object *in);
++#else
++#define yaffs_CheckFileSanity(in)
++#endif
++
++static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
++static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
++
++static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
++
++static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
++ yaffs_ExtendedTags *tags);
++
++static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
++ unsigned pos);
++static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
++ yaffs_FileStructure *fStruct,
++ __u32 chunkId);
++
++static void yaffs_SkipRestOfBlock(yaffs_Device *dev);
++static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
++ int chunkInNAND,
++ const __u8 *data,
++ yaffs_ExtendedTags *tags);
++
++/* Function to calculate chunk and offset */
++
++static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
++ __u32 *offsetOut)
++{
++ int chunk;
++ __u32 offset;
++
++ chunk = (__u32)(addr >> dev->chunkShift);
++
++ if (dev->chunkDiv == 1) {
++ /* easy power of 2 case */
++ offset = (__u32)(addr & dev->chunkMask);
++ } else {
++ /* Non power-of-2 case */
++
++ loff_t chunkBase;
++
++ chunk /= dev->chunkDiv;
++
++ chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk;
++ offset = (__u32)(addr - chunkBase);
++ }
++
++ *chunkOut = chunk;
++ *offsetOut = offset;
++}
++
++/* Function to return the number of shifts for a power of 2 greater than or
++ * equal to the given number
++ * Note we don't try to cater for all possible numbers and this does not have to
++ * be hellishly efficient.
++ */
++
++static __u32 ShiftsGE(__u32 x)
++{
++ int extraBits;
++ int nShifts;
++
++ nShifts = extraBits = 0;
++
++ while (x > 1) {
++ if (x & 1)
++ extraBits++;
++ x >>= 1;
++ nShifts++;
++ }
++
++ if (extraBits)
++ nShifts++;
++
++ return nShifts;
++}
++
++/* Function to return the number of shifts to get a 1 in bit 0
++ */
++
++static __u32 Shifts(__u32 x)
++{
++ int nShifts;
++
++ nShifts = 0;
++
++ if (!x)
++ return 0;
++
++ while (!(x&1)) {
++ x >>= 1;
++ nShifts++;
++ }
++
++ return nShifts;
++}
++
++
++
++/*
++ * Temporary buffer manipulations.
++ */
++
++static int yaffs_InitialiseTempBuffers(yaffs_Device *dev)
++{
++ int i;
++ __u8 *buf = (__u8 *)1;
++
++ memset(dev->tempBuffer, 0, sizeof(dev->tempBuffer));
++
++ for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
++ dev->tempBuffer[i].line = 0; /* not in use */
++ dev->tempBuffer[i].buffer = buf =
++ YMALLOC_DMA(dev->totalBytesPerChunk);
++ }
++
++ return buf ? YAFFS_OK : YAFFS_FAIL;
++}
++
++__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo)
++{
++ int i, j;
++
++ dev->tempInUse++;
++ if (dev->tempInUse > dev->maxTemp)
++ dev->maxTemp = dev->tempInUse;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->tempBuffer[i].line == 0) {
++ dev->tempBuffer[i].line = lineNo;
++ if ((i + 1) > dev->maxTemp) {
++ dev->maxTemp = i + 1;
++ for (j = 0; j <= i; j++)
++ dev->tempBuffer[j].maxLine =
++ dev->tempBuffer[j].line;
++ }
++
++ return dev->tempBuffer[i].buffer;
++ }
++ }
++
++ T(YAFFS_TRACE_BUFFERS,
++ (TSTR("Out of temp buffers at line %d, other held by lines:"),
++ lineNo));
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
++ T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line));
++
++ T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));
++
++ /*
++ * If we got here then we have to allocate an unmanaged one
++ * This is not good.
++ */
++
++ dev->unmanagedTempAllocations++;
++ return YMALLOC(dev->nDataBytesPerChunk);
++
++}
++
++void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer,
++ int lineNo)
++{
++ int i;
++
++ dev->tempInUse--;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->tempBuffer[i].buffer == buffer) {
++ dev->tempBuffer[i].line = 0;
++ return;
++ }
++ }
++
++ if (buffer) {
++ /* assume it is an unmanaged one. */
++ T(YAFFS_TRACE_BUFFERS,
++ (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),
++ lineNo));
++ YFREE(buffer);
++ dev->unmanagedTempDeallocations++;
++ }
++
++}
++
++/*
++ * Determine if we have a managed buffer.
++ */
++int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer)
++{
++ int i;
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++ if (dev->tempBuffer[i].buffer == buffer)
++ return 1;
++ }
++
++ for (i = 0; i < dev->nShortOpCaches; i++) {
++ if (dev->srCache[i].data == buffer)
++ return 1;
++ }
++
++ if (buffer == dev->checkpointBuffer)
++ return 1;
++
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR)));
++ return 0;
++}
++
++
++
++/*
++ * Chunk bitmap manipulations
++ */
++
++static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
++{
++ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
++ blk));
++ YBUG();
++ }
++ return dev->chunkBits +
++ (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
++}
++
++static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
++{
++ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
++ chunk < 0 || chunk >= dev->nChunksPerBlock) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
++ blk, chunk));
++ YBUG();
++ }
++}
++
++static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
++{
++ __u8 *blkBits = yaffs_BlockBits(dev, blk);
++
++ memset(blkBits, 0, dev->chunkBitmapStride);
++}
++
++static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
++{
++ __u8 *blkBits = yaffs_BlockBits(dev, blk);
++
++ yaffs_VerifyChunkBitId(dev, blk, chunk);
++
++ blkBits[chunk / 8] &= ~(1 << (chunk & 7));
++}
++
++static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
++{
++ __u8 *blkBits = yaffs_BlockBits(dev, blk);
++
++ yaffs_VerifyChunkBitId(dev, blk, chunk);
++
++ blkBits[chunk / 8] |= (1 << (chunk & 7));
++}
++
++static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
++{
++ __u8 *blkBits = yaffs_BlockBits(dev, blk);
++ yaffs_VerifyChunkBitId(dev, blk, chunk);
++
++ return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
++}
++
++static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
++{
++ __u8 *blkBits = yaffs_BlockBits(dev, blk);
++ int i;
++ for (i = 0; i < dev->chunkBitmapStride; i++) {
++ if (*blkBits)
++ return 1;
++ blkBits++;
++ }
++ return 0;
++}
++
++static int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
++{
++ __u8 *blkBits = yaffs_BlockBits(dev, blk);
++ int i;
++ int n = 0;
++ for (i = 0; i < dev->chunkBitmapStride; i++) {
++ __u8 x = *blkBits;
++ while (x) {
++ if (x & 1)
++ n++;
++ x >>= 1;
++ }
++
++ blkBits++;
++ }
++ return n;
++}
++
++/*
++ * Verification code
++ */
++
++static int yaffs_SkipVerification(yaffs_Device *dev)
++{
++ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_SkipFullVerification(yaffs_Device *dev)
++{
++ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
++}
++
++static int yaffs_SkipNANDVerification(yaffs_Device *dev)
++{
++ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
++}
++
++static const char *blockStateName[] = {
++"Unknown",
++"Needs scanning",
++"Scanning",
++"Empty",
++"Allocating",
++"Full",
++"Dirty",
++"Checkpoint",
++"Collecting",
++"Dead"
++};
++
++static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
++{
++ int actuallyUsed;
++ int inUse;
++
++ if (yaffs_SkipVerification(dev))
++ return;
++
++ /* Report illegal runtime states */
++ if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
++
++ switch (bi->blockState) {
++ case YAFFS_BLOCK_STATE_UNKNOWN:
++ case YAFFS_BLOCK_STATE_SCANNING:
++ case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
++ n, blockStateName[bi->blockState]));
++ }
++
++ /* Check pages in use and soft deletions are legal */
++
++ actuallyUsed = bi->pagesInUse - bi->softDeletions;
++
++ if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||
++ bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||
++ actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)
++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
++ n, bi->pagesInUse, bi->softDeletions));
++
++
++ /* Check chunk bitmap legal */
++ inUse = yaffs_CountChunkBits(dev, n);
++ if (inUse != bi->pagesInUse)
++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
++ n, bi->pagesInUse, inUse));
++
++ /* Check that the sequence number is valid.
++ * Ten million is legal, but is very unlikely
++ */
++ if (dev->isYaffs2 &&
++ (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
++ (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
++ n, bi->sequenceNumber));
++}
++
++static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
++ int n)
++{
++ yaffs_VerifyBlock(dev, bi, n);
++
++ /* After collection the block should be in the erased state */
++ /* This will need to change if we do partial gc */
++
++ if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
++ bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
++ T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
++ n, bi->blockState));
++ }
++}
++
++static void yaffs_VerifyBlocks(yaffs_Device *dev)
++{
++ int i;
++ int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
++ int nIllegalBlockStates = 0;
++
++ if (yaffs_SkipVerification(dev))
++ return;
++
++ memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
++
++ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
++ yaffs_VerifyBlock(dev, bi, i);
++
++ if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
++ nBlocksPerState[bi->blockState]++;
++ else
++ nIllegalBlockStates++;
++ }
++
++ T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
++ T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
++
++ T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
++ if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
++ T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
++
++ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("%s %d blocks"TENDSTR),
++ blockStateName[i], nBlocksPerState[i]));
++
++ if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
++ dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
++
++ if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
++ dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
++
++ if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
++ nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
++
++ T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
++
++}
++
++/*
++ * Verify the object header. oh must be valid, but obj and tags may be NULL in which
++ * case those tests will not be performed.
++ */
++static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
++{
++ if (obj && yaffs_SkipVerification(obj->myDev))
++ return;
++
++ if (!(tags && obj && oh)) {
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
++ tags, obj, oh));
++ return;
++ }
++
++ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
++ oh->type > YAFFS_OBJECT_TYPE_MAX)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
++ tags->objectId, oh->type));
++
++ if (tags->objectId != obj->objectId)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
++ tags->objectId, obj->objectId));
++
++
++ /*
++ * Check that the object's parent ids match if parentCheck requested.
++ *
++ * Tests do not apply to the root object.
++ */
++
++ if (parentCheck && tags->objectId > 1 && !obj->parent)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
++ tags->objectId, oh->parentObjectId));
++
++ if (parentCheck && obj->parent &&
++ oh->parentObjectId != obj->parent->objectId &&
++ (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
++ obj->parent->objectId != YAFFS_OBJECTID_DELETED))
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
++ tags->objectId, oh->parentObjectId, obj->parent->objectId));
++
++ if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d header name is NULL"TENDSTR),
++ obj->objectId));
++
++ if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d header name is 0xFF"TENDSTR),
++ obj->objectId));
++}
++
++
++
++static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
++ __u32 level, int chunkOffset)
++{
++ int i;
++ yaffs_Device *dev = obj->myDev;
++ int ok = 1;
++
++ if (tn) {
++ if (level > 0) {
++
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
++ if (tn->internal[i]) {
++ ok = yaffs_VerifyTnodeWorker(obj,
++ tn->internal[i],
++ level - 1,
++ (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
++ }
++ }
++ } else if (level == 0) {
++ yaffs_ExtendedTags tags;
++ __u32 objectId = obj->objectId;
++
++ chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
++
++ for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
++ __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
++
++ if (theChunk > 0) {
++ /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
++ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
++ if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
++ T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
++ objectId, chunkOffset, theChunk,
++ tags.objectId, tags.chunkId));
++ }
++ }
++ chunkOffset++;
++ }
++ }
++ }
++
++ return ok;
++
++}
++
++
++static void yaffs_VerifyFile(yaffs_Object *obj)
++{
++ int requiredTallness;
++ int actualTallness;
++ __u32 lastChunk;
++ __u32 x;
++ __u32 i;
++ yaffs_Device *dev;
++ yaffs_ExtendedTags tags;
++ yaffs_Tnode *tn;
++ __u32 objectId;
++
++ if (!obj)
++ return;
++
++ if (yaffs_SkipVerification(obj->myDev))
++ return;
++
++ dev = obj->myDev;
++ objectId = obj->objectId;
++
++ /* Check file size is consistent with tnode depth */
++ lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
++ x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
++ requiredTallness = 0;
++ while (x > 0) {
++ x >>= YAFFS_TNODES_INTERNAL_BITS;
++ requiredTallness++;
++ }
++
++ actualTallness = obj->variant.fileVariant.topLevel;
++
++ if (requiredTallness > actualTallness)
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
++ obj->objectId, actualTallness, requiredTallness));
++
++
++ /* Check that the chunks in the tnode tree are all correct.
++ * We do this by scanning through the tnode tree and
++ * checking the tags for every chunk match.
++ */
++
++ if (yaffs_SkipNANDVerification(dev))
++ return;
++
++ for (i = 1; i <= lastChunk; i++) {
++ tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
++
++ if (tn) {
++ __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
++ if (theChunk > 0) {
++ /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
++ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
++ if (tags.objectId != objectId || tags.chunkId != i) {
++ T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
++ objectId, i, theChunk,
++ tags.objectId, tags.chunkId));
++ }
++ }
++ }
++ }
++}
++
++
++static void yaffs_VerifyHardLink(yaffs_Object *obj)
++{
++ if (obj && yaffs_SkipVerification(obj->myDev))
++ return;
++
++ /* Verify sane equivalent object */
++}
++
++static void yaffs_VerifySymlink(yaffs_Object *obj)
++{
++ if (obj && yaffs_SkipVerification(obj->myDev))
++ return;
++
++ /* Verify symlink string */
++}
++
++static void yaffs_VerifySpecial(yaffs_Object *obj)
++{
++ if (obj && yaffs_SkipVerification(obj->myDev))
++ return;
++}
++
++static void yaffs_VerifyObject(yaffs_Object *obj)
++{
++ yaffs_Device *dev;
++
++ __u32 chunkMin;
++ __u32 chunkMax;
++
++ __u32 chunkIdOk;
++ __u32 chunkInRange;
++ __u32 chunkShouldNotBeDeleted;
++ __u32 chunkValid;
++
++ if (!obj)
++ return;
++
++ if (obj->beingCreated)
++ return;
++
++ dev = obj->myDev;
++
++ if (yaffs_SkipVerification(dev))
++ return;
++
++ /* Check sane object header chunk */
++
++ chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
++ chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
++
++ chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
++ chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
++ chunkValid = chunkInRange &&
++ yaffs_CheckChunkBit(dev,
++ obj->hdrChunk / dev->nChunksPerBlock,
++ obj->hdrChunk % dev->nChunksPerBlock);
++ chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
++
++ if (!obj->fake &&
++ (!chunkIdOk || chunkShouldNotBeDeleted)) {
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
++ obj->objectId, obj->hdrChunk,
++ chunkIdOk ? "" : ",out of range",
++ chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
++ }
++
++ if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
++ yaffs_ExtendedTags tags;
++ yaffs_ObjectHeader *oh;
++ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
++
++ oh = (yaffs_ObjectHeader *)buffer;
++
++ yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
++ &tags);
++
++ yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
++
++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
++ }
++
++ /* Verify it has a parent */
++ if (obj && !obj->fake &&
++ (!obj->parent || obj->parent->myDev != dev)) {
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
++ obj->objectId, obj->parent));
++ }
++
++ /* Verify parent is a directory */
++ if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
++ obj->objectId, obj->parent->variantType));
++ }
++
++ switch (obj->variantType) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ yaffs_VerifyFile(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ yaffs_VerifySymlink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ yaffs_VerifyDirectory(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ yaffs_VerifyHardLink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ yaffs_VerifySpecial(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ default:
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Obj %d has illegaltype %d"TENDSTR),
++ obj->objectId, obj->variantType));
++ break;
++ }
++}
++
++static void yaffs_VerifyObjects(yaffs_Device *dev)
++{
++ yaffs_Object *obj;
++ int i;
++ struct ylist_head *lh;
++
++ if (yaffs_SkipVerification(dev))
++ return;
++
++ /* Iterate through the objects in each hash entry */
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ ylist_for_each(lh, &dev->objectBucket[i].list) {
++ if (lh) {
++ obj = ylist_entry(lh, yaffs_Object, hashLink);
++ yaffs_VerifyObject(obj);
++ }
++ }
++ }
++}
++
++
++/*
++ * Simple hash function. Needs to have a reasonable spread
++ */
++
++static Y_INLINE int yaffs_HashFunction(int n)
++{
++ n = abs(n);
++ return n % YAFFS_NOBJECT_BUCKETS;
++}
++
++/*
++ * Access functions to useful fake objects.
++ * Note that root might have a presence in NAND if permissions are set.
++ */
++
++yaffs_Object *yaffs_Root(yaffs_Device *dev)
++{
++ return dev->rootDir;
++}
++
++yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
++{
++ return dev->lostNFoundDir;
++}
++
++
++/*
++ * Erased NAND checking functions
++ */
++
++int yaffs_CheckFF(__u8 *buffer, int nBytes)
++{
++ /* Horrible, slow implementation */
++ while (nBytes--) {
++ if (*buffer != 0xFF)
++ return 0;
++ buffer++;
++ }
++ return 1;
++}
++
++static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
++ int chunkInNAND)
++{
++ int retval = YAFFS_OK;
++ __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
++ yaffs_ExtendedTags tags;
++ int result;
++
++ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
++
++ if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
++ retval = YAFFS_FAIL;
++
++ if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
++ T(YAFFS_TRACE_NANDACCESS,
++ (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
++ retval = YAFFS_FAIL;
++ }
++
++ yaffs_ReleaseTempBuffer(dev, data, __LINE__);
++
++ return retval;
++
++}
++
++
++static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
++ int chunkInNAND,
++ const __u8 *data,
++ yaffs_ExtendedTags *tags)
++{
++ int retval = YAFFS_OK;
++ yaffs_ExtendedTags tempTags;
++ __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
++ int result;
++
++ result = yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,&tempTags);
++ if(memcmp(buffer,data,dev->nDataBytesPerChunk) ||
++ tempTags.objectId != tags->objectId ||
++ tempTags.chunkId != tags->chunkId ||
++ tempTags.byteCount != tags->byteCount)
++ retval = YAFFS_FAIL;
++
++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
++
++ return retval;
++}
++
++static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
++ const __u8 *data,
++ yaffs_ExtendedTags *tags,
++ int useReserve)
++{
++ int attempts = 0;
++ int writeOk = 0;
++ int chunk;
++
++ yaffs_InvalidateCheckpoint(dev);
++
++ do {
++ yaffs_BlockInfo *bi = 0;
++ int erasedOk = 0;
++
++ chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
++ if (chunk < 0) {
++ /* no space */
++ break;
++ }
++
++ /* First check this chunk is erased, if it needs
++ * checking. The checking policy (unless forced
++ * always on) is as follows:
++ *
++ * Check the first page we try to write in a block.
++ * If the check passes then we don't need to check any
++ * more. If the check fails, we check again...
++ * If the block has been erased, we don't need to check.
++ *
++ * However, if the block has been prioritised for gc,
++ * then we think there might be something odd about
++ * this block and stop using it.
++ *
++ * Rationale: We should only ever see chunks that have
++ * not been erased if there was a partially written
++ * chunk due to power loss. This checking policy should
++ * catch that case with very few checks and thus save a
++ * lot of checks that are most likely not needed.
++ *
++ * Mods to the above
++ * If an erase check fails or the write fails we skip the
++ * rest of the block.
++ */
++
++ /* let's give it a try */
++ attempts++;
++
++#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
++ bi->skipErasedCheck = 0;
++#endif
++ if (!bi->skipErasedCheck) {
++ erasedOk = yaffs_CheckChunkErased(dev, chunk);
++ if (erasedOk != YAFFS_OK) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("**>> yaffs chunk %d was not erased"
++ TENDSTR), chunk));
++
++ /* If not erased, delete this one,
++ * skip rest of block and
++ * try another chunk */
++ yaffs_DeleteChunk(dev,chunk,1,__LINE__);
++ yaffs_SkipRestOfBlock(dev);
++ continue;
++ }
++ }
++
++ writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
++ data, tags);
++
++ if(!bi->skipErasedCheck)
++ writeOk = yaffs_VerifyChunkWritten(dev, chunk, data, tags);
++
++ if (writeOk != YAFFS_OK) {
++ /* Clean up aborted write, skip to next block and
++ * try another chunk */
++ yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
++ continue;
++ }
++
++ bi->skipErasedCheck = 1;
++
++ /* Copy the data into the robustification buffer */
++ yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
++
++ } while (writeOk != YAFFS_OK &&
++ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
++
++ if (!writeOk)
++ chunk = -1;
++
++ if (attempts > 1) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("**>> yaffs write required %d attempts" TENDSTR),
++ attempts));
++
++ dev->nRetriedWrites += (attempts - 1);
++ }
++
++ return chunk;
++}
++
++/*
++ * Block retiring for handling a broken block.
++ */
++
++static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
++{
++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
++
++ yaffs_InvalidateCheckpoint(dev);
++
++ if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
++ if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR(
++ "yaffs: Failed to mark bad and erase block %d"
++ TENDSTR), blockInNAND));
++ } else {
++ yaffs_ExtendedTags tags;
++ int chunkId = blockInNAND * dev->nChunksPerBlock;
++
++ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
++
++ memset(buffer, 0xff, dev->nDataBytesPerChunk);
++ yaffs_InitialiseTags(&tags);
++ tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
++ if (dev->writeChunkWithTagsToNAND(dev, chunkId -
++ dev->chunkOffset, buffer, &tags) != YAFFS_OK)
++ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
++ TCONT("write bad block marker to block %d")
++ TENDSTR), blockInNAND));
++
++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
++ }
++ }
++
++ bi->blockState = YAFFS_BLOCK_STATE_DEAD;
++ bi->gcPrioritise = 0;
++ bi->needsRetiring = 0;
++
++ dev->nRetiredBlocks++;
++}
++
++/*
++ * Functions for robustisizing TODO
++ *
++ */
++
++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
++ const __u8 *data,
++ const yaffs_ExtendedTags *tags)
++{
++}
++
++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
++ const yaffs_ExtendedTags *tags)
++{
++}
++
++void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
++{
++ if (!bi->gcPrioritise) {
++ bi->gcPrioritise = 1;
++ dev->hasPendingPrioritisedGCs = 1;
++ bi->chunkErrorStrikes++;
++
++ if (bi->chunkErrorStrikes > 3) {
++ bi->needsRetiring = 1; /* Too many stikes, so retire this */
++ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
++
++ }
++ }
++}
++
++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
++ int erasedOk)
++{
++ int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
++
++ yaffs_HandleChunkError(dev, bi);
++
++ if (erasedOk) {
++ /* Was an actual write failure, so mark the block for retirement */
++ bi->needsRetiring = 1;
++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
++ }
++
++ /* Delete the chunk */
++ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
++ yaffs_SkipRestOfBlock(dev);
++}
++
++
++/*---------------- Name handling functions ------------*/
++
++static __u16 yaffs_CalcNameSum(const YCHAR *name)
++{
++ __u16 sum = 0;
++ __u16 i = 1;
++
++ const YUCHAR *bname = (const YUCHAR *) name;
++ if (bname) {
++ while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
++
++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
++ sum += yaffs_toupper(*bname) * i;
++#else
++ sum += (*bname) * i;
++#endif
++ i++;
++ bname++;
++ }
++ }
++ return sum;
++}
++
++static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
++{
++#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
++ memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
++ if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH)
++ yaffs_strcpy(obj->shortName, name);
++ else
++ obj->shortName[0] = _Y('\0');
++#endif
++ obj->sum = yaffs_CalcNameSum(name);
++}
++
++/*-------------------- TNODES -------------------
++
++ * List of spare tnodes
++ * The list is hooked together using the first pointer
++ * in the tnode.
++ */
++
++/* yaffs_CreateTnodes creates a bunch more tnodes and
++ * adds them to the tnode free list.
++ * Don't use this function directly
++ */
++
++static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
++{
++ int i;
++ int tnodeSize;
++ yaffs_Tnode *newTnodes;
++ __u8 *mem;
++ yaffs_Tnode *curr;
++ yaffs_Tnode *next;
++ yaffs_TnodeList *tnl;
++
++ if (nTnodes < 1)
++ return YAFFS_OK;
++
++ /* Calculate the tnode size in bytes for variable width tnode support.
++ * Must be a multiple of 32-bits */
++ tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
++
++ if (tnodeSize < sizeof(yaffs_Tnode))
++ tnodeSize = sizeof(yaffs_Tnode);
++
++ /* make these things */
++
++ newTnodes = YMALLOC(nTnodes * tnodeSize);
++ mem = (__u8 *)newTnodes;
++
++ if (!newTnodes) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ /* Hook them into the free list */
++#if 0
++ for (i = 0; i < nTnodes - 1; i++) {
++ newTnodes[i].internal[0] = &newTnodes[i + 1];
++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
++ newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
++#endif
++ }
++
++ newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
++ newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
++#endif
++ dev->freeTnodes = newTnodes;
++#else
++ /* New hookup for wide tnodes */
++ for (i = 0; i < nTnodes - 1; i++) {
++ curr = (yaffs_Tnode *) &mem[i * tnodeSize];
++ next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
++ curr->internal[0] = next;
++ }
++
++ curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
++ curr->internal[0] = dev->freeTnodes;
++ dev->freeTnodes = (yaffs_Tnode *)mem;
++
++#endif
++
++
++ dev->nFreeTnodes += nTnodes;
++ dev->nTnodesCreated += nTnodes;
++
++ /* Now add this bunch of tnodes to a list for freeing up.
++ * NB If we can't add this to the management list it isn't fatal
++ * but it just means we can't free this bunch of tnodes later.
++ */
++
++ tnl = YMALLOC(sizeof(yaffs_TnodeList));
++ if (!tnl) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs: Could not add tnodes to management list" TENDSTR)));
++ return YAFFS_FAIL;
++ } else {
++ tnl->tnodes = newTnodes;
++ tnl->next = dev->allocatedTnodeList;
++ dev->allocatedTnodeList = tnl;
++ }
++
++ T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
++
++ return YAFFS_OK;
++}
++
++/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
++
++static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
++{
++ yaffs_Tnode *tn = NULL;
++
++ /* If there are none left make more */
++ if (!dev->freeTnodes)
++ yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
++
++ if (dev->freeTnodes) {
++ tn = dev->freeTnodes;
++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
++ if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
++ /* Hoosterman, this thing looks like it isn't in the list */
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
++ }
++#endif
++ dev->freeTnodes = dev->freeTnodes->internal[0];
++ dev->nFreeTnodes--;
++ }
++
++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
++
++ return tn;
++}
++
++static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
++{
++ yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
++ int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
++
++ if (tnodeSize < sizeof(yaffs_Tnode))
++ tnodeSize = sizeof(yaffs_Tnode);
++
++ if (tn)
++ memset(tn, 0, tnodeSize);
++
++ return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
++{
++ if (tn) {
++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
++ if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
++ /* Hoosterman, this thing looks like it is already in the list */
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
++ }
++ tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
++#endif
++ tn->internal[0] = dev->freeTnodes;
++ dev->freeTnodes = tn;
++ dev->nFreeTnodes++;
++ }
++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
++}
++
++static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)
++{
++ /* Free the list of allocated tnodes */
++ yaffs_TnodeList *tmp;
++
++ while (dev->allocatedTnodeList) {
++ tmp = dev->allocatedTnodeList->next;
++
++ YFREE(dev->allocatedTnodeList->tnodes);
++ YFREE(dev->allocatedTnodeList);
++ dev->allocatedTnodeList = tmp;
++
++ }
++
++ dev->freeTnodes = NULL;
++ dev->nFreeTnodes = 0;
++ dev->nTnodesCreated = 0;
++}
++
++static void yaffs_InitialiseTnodes(yaffs_Device *dev)
++{
++ dev->allocatedTnodeList = NULL;
++ dev->freeTnodes = NULL;
++ dev->nFreeTnodes = 0;
++ dev->nTnodesCreated = 0;
++}
++
++
++void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
++ unsigned val)
++{
++ __u32 *map = (__u32 *)tn;
++ __u32 bitInMap;
++ __u32 bitInWord;
++ __u32 wordInMap;
++ __u32 mask;
++
++ pos &= YAFFS_TNODES_LEVEL0_MASK;
++ val >>= dev->chunkGroupBits;
++
++ bitInMap = pos * dev->tnodeWidth;
++ wordInMap = bitInMap / 32;
++ bitInWord = bitInMap & (32 - 1);
++
++ mask = dev->tnodeMask << bitInWord;
++
++ map[wordInMap] &= ~mask;
++ map[wordInMap] |= (mask & (val << bitInWord));
++
++ if (dev->tnodeWidth > (32 - bitInWord)) {
++ bitInWord = (32 - bitInWord);
++ wordInMap++;;
++ mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
++ map[wordInMap] &= ~mask;
++ map[wordInMap] |= (mask & (val >> bitInWord));
++ }
++}
++
++static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
++ unsigned pos)
++{
++ __u32 *map = (__u32 *)tn;
++ __u32 bitInMap;
++ __u32 bitInWord;
++ __u32 wordInMap;
++ __u32 val;
++
++ pos &= YAFFS_TNODES_LEVEL0_MASK;
++
++ bitInMap = pos * dev->tnodeWidth;
++ wordInMap = bitInMap / 32;
++ bitInWord = bitInMap & (32 - 1);
++
++ val = map[wordInMap] >> bitInWord;
++
++ if (dev->tnodeWidth > (32 - bitInWord)) {
++ bitInWord = (32 - bitInWord);
++ wordInMap++;;
++ val |= (map[wordInMap] << bitInWord);
++ }
++
++ val &= dev->tnodeMask;
++ val <<= dev->chunkGroupBits;
++
++ return val;
++}
++
++/* ------------------- End of individual tnode manipulation -----------------*/
++
++/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
++ * The look up tree is represented by the top tnode and the number of topLevel
++ * in the tree. 0 means only the level 0 tnode is in the tree.
++ */
++
++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
++static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
++ yaffs_FileStructure *fStruct,
++ __u32 chunkId)
++{
++ yaffs_Tnode *tn = fStruct->top;
++ __u32 i;
++ int requiredTallness;
++ int level = fStruct->topLevel;
++
++ /* Check sane level and chunk Id */
++ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
++ return NULL;
++
++ if (chunkId > YAFFS_MAX_CHUNK_ID)
++ return NULL;
++
++ /* First check we're tall enough (ie enough topLevel) */
++
++ i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
++ requiredTallness = 0;
++ while (i) {
++ i >>= YAFFS_TNODES_INTERNAL_BITS;
++ requiredTallness++;
++ }
++
++ if (requiredTallness > fStruct->topLevel)
++ return NULL; /* Not tall enough, so we can't find it */
++
++ /* Traverse down to level 0 */
++ while (level > 0 && tn) {
++ tn = tn->internal[(chunkId >>
++ (YAFFS_TNODES_LEVEL0_BITS +
++ (level - 1) *
++ YAFFS_TNODES_INTERNAL_BITS)) &
++ YAFFS_TNODES_INTERNAL_MASK];
++ level--;
++ }
++
++ return tn;
++}
++
++/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
++ * This happens in two steps:
++ * 1. If the tree isn't tall enough, then make it taller.
++ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
++ *
++ * Used when modifying the tree.
++ *
++ * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
++ * be plugged into the ttree.
++ */
++
++static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
++ yaffs_FileStructure *fStruct,
++ __u32 chunkId,
++ yaffs_Tnode *passedTn)
++{
++ int requiredTallness;
++ int i;
++ int l;
++ yaffs_Tnode *tn;
++
++ __u32 x;
++
++
++ /* Check sane level and page Id */
++ if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
++ return NULL;
++
++ if (chunkId > YAFFS_MAX_CHUNK_ID)
++ return NULL;
++
++ /* First check we're tall enough (ie enough topLevel) */
++
++ x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
++ requiredTallness = 0;
++ while (x) {
++ x >>= YAFFS_TNODES_INTERNAL_BITS;
++ requiredTallness++;
++ }
++
++
++ if (requiredTallness > fStruct->topLevel) {
++ /* Not tall enough, gotta make the tree taller */
++ for (i = fStruct->topLevel; i < requiredTallness; i++) {
++
++ tn = yaffs_GetTnode(dev);
++
++ if (tn) {
++ tn->internal[0] = fStruct->top;
++ fStruct->top = tn;
++ fStruct->topLevel++;
++ } else {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("yaffs: no more tnodes" TENDSTR)));
++ return NULL;
++ }
++ }
++ }
++
++ /* Traverse down to level 0, adding anything we need */
++
++ l = fStruct->topLevel;
++ tn = fStruct->top;
++
++ if (l > 0) {
++ while (l > 0 && tn) {
++ x = (chunkId >>
++ (YAFFS_TNODES_LEVEL0_BITS +
++ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
++ YAFFS_TNODES_INTERNAL_MASK;
++
++
++ if ((l > 1) && !tn->internal[x]) {
++ /* Add missing non-level-zero tnode */
++ tn->internal[x] = yaffs_GetTnode(dev);
++ if(!tn->internal[x])
++ return NULL;
++
++ } else if (l == 1) {
++ /* Looking from level 1 at level 0 */
++ if (passedTn) {
++ /* If we already have one, then release it.*/
++ if (tn->internal[x])
++ yaffs_FreeTnode(dev, tn->internal[x]);
++ tn->internal[x] = passedTn;
++
++ } else if (!tn->internal[x]) {
++ /* Don't have one, none passed in */
++ tn->internal[x] = yaffs_GetTnode(dev);
++ if(!tn->internal[x])
++ return NULL;
++ }
++ }
++
++ tn = tn->internal[x];
++ l--;
++ }
++ } else {
++ /* top is level 0 */
++ if (passedTn) {
++ memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
++ yaffs_FreeTnode(dev, passedTn);
++ }
++ }
++
++ return tn;
++}
++
++static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
++ yaffs_ExtendedTags *tags, int objectId,
++ int chunkInInode)
++{
++ int j;
++
++ for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
++ if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
++ theChunk % dev->nChunksPerBlock)) {
++
++ if(dev->chunkGroupSize == 1)
++ return theChunk;
++ else {
++ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
++ tags);
++ if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
++ /* found it; */
++ return theChunk;
++ }
++ }
++ }
++ theChunk++;
++ }
++ return -1;
++}
++
++
++/* DeleteWorker scans backwards through the tnode tree and deletes all the
++ * chunks and tnodes in the file
++ * Returns 1 if the tree was deleted.
++ * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
++ */
++
++static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
++ int chunkOffset, int *limit)
++{
++ int i;
++ int chunkInInode;
++ int theChunk;
++ yaffs_ExtendedTags tags;
++ int foundChunk;
++ yaffs_Device *dev = in->myDev;
++
++ int allDone = 1;
++
++ if (tn) {
++ if (level > 0) {
++ for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
++ i--) {
++ if (tn->internal[i]) {
++ if (limit && (*limit) < 0) {
++ allDone = 0;
++ } else {
++ allDone =
++ yaffs_DeleteWorker(in,
++ tn->
++ internal
++ [i],
++ level -
++ 1,
++ (chunkOffset
++ <<
++ YAFFS_TNODES_INTERNAL_BITS)
++ + i,
++ limit);
++ }
++ if (allDone) {
++ yaffs_FreeTnode(dev,
++ tn->
++ internal[i]);
++ tn->internal[i] = NULL;
++ }
++ }
++ }
++ return (allDone) ? 1 : 0;
++ } else if (level == 0) {
++ int hitLimit = 0;
++
++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
++ i--) {
++ theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
++ if (theChunk) {
++
++ chunkInInode = (chunkOffset <<
++ YAFFS_TNODES_LEVEL0_BITS) + i;
++
++ foundChunk =
++ yaffs_FindChunkInGroup(dev,
++ theChunk,
++ &tags,
++ in->objectId,
++ chunkInInode);
++
++ if (foundChunk > 0) {
++ yaffs_DeleteChunk(dev,
++ foundChunk, 1,
++ __LINE__);
++ in->nDataChunks--;
++ if (limit) {
++ *limit = *limit - 1;
++ if (*limit <= 0)
++ hitLimit = 1;
++ }
++
++ }
++
++ yaffs_LoadLevel0Tnode(dev, tn, i, 0);
++ }
++
++ }
++ return (i < 0) ? 1 : 0;
++
++ }
++
++ }
++
++ return 1;
++
++}
++
++static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
++{
++ yaffs_BlockInfo *theBlock;
++
++ T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
++
++ theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
++ if (theBlock) {
++ theBlock->softDeletions++;
++ dev->nFreeChunks++;
++ }
++}
++
++/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
++ * All soft deleting does is increment the block's softdelete count and pulls the chunk out
++ * of the tnode.
++ * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
++ */
++
++static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
++ __u32 level, int chunkOffset)
++{
++ int i;
++ int theChunk;
++ int allDone = 1;
++ yaffs_Device *dev = in->myDev;
++
++ if (tn) {
++ if (level > 0) {
++
++ for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
++ i--) {
++ if (tn->internal[i]) {
++ allDone =
++ yaffs_SoftDeleteWorker(in,
++ tn->
++ internal[i],
++ level - 1,
++ (chunkOffset
++ <<
++ YAFFS_TNODES_INTERNAL_BITS)
++ + i);
++ if (allDone) {
++ yaffs_FreeTnode(dev,
++ tn->
++ internal[i]);
++ tn->internal[i] = NULL;
++ } else {
++ /* Hoosterman... how could this happen? */
++ }
++ }
++ }
++ return (allDone) ? 1 : 0;
++ } else if (level == 0) {
++
++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
++ theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
++ if (theChunk) {
++ /* Note this does not find the real chunk, only the chunk group.
++ * We make an assumption that a chunk group is not larger than
++ * a block.
++ */
++ yaffs_SoftDeleteChunk(dev, theChunk);
++ yaffs_LoadLevel0Tnode(dev, tn, i, 0);
++ }
++
++ }
++ return 1;
++
++ }
++
++ }
++
++ return 1;
++
++}
++
++static void yaffs_SoftDeleteFile(yaffs_Object *obj)
++{
++ if (obj->deleted &&
++ obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
++ if (obj->nDataChunks <= 0) {
++ /* Empty file with no duplicate object headers, just delete it immediately */
++ yaffs_FreeTnode(obj->myDev,
++ obj->variant.fileVariant.top);
++ obj->variant.fileVariant.top = NULL;
++ T(YAFFS_TRACE_TRACING,
++ (TSTR("yaffs: Deleting empty file %d" TENDSTR),
++ obj->objectId));
++ yaffs_DoGenericObjectDeletion(obj);
++ } else {
++ yaffs_SoftDeleteWorker(obj,
++ obj->variant.fileVariant.top,
++ obj->variant.fileVariant.
++ topLevel, 0);
++ obj->softDeleted = 1;
++ }
++ }
++}
++
++/* Pruning removes any part of the file structure tree that is beyond the
++ * bounds of the file (ie that does not point to chunks).
++ *
++ * A file should only get pruned when its size is reduced.
++ *
++ * Before pruning, the chunks must be pulled from the tree and the
++ * level 0 tnode entries must be zeroed out.
++ * Could also use this for file deletion, but that's probably better handled
++ * by a special case.
++ *
++ * This function is recursive. For levels > 0 the function is called again on
++ * any sub-tree. For level == 0 we just check if the sub-tree has data.
++ * If there is no data in a subtree then it is pruned.
++ */
++
++static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
++ __u32 level, int del0)
++{
++ int i;
++ int hasData;
++
++ if (tn) {
++ hasData = 0;
++
++ if(level > 0){
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
++ if (tn->internal[i]) {
++ tn->internal[i] =
++ yaffs_PruneWorker(dev, tn->internal[i],
++ level - 1,
++ (i == 0) ? del0 : 1);
++ }
++
++ if (tn->internal[i])
++ hasData++;
++ }
++ } else {
++ int tnodeSize;
++ __u32 *map = (__u32 *)tn;
++ tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
++
++ if (tnodeSize < sizeof(yaffs_Tnode))
++ tnodeSize = sizeof(yaffs_Tnode);
++ tnodeSize /= sizeof(__u32);
++
++ for(i = 0; !hasData && i < tnodeSize; i++){
++ if(map[i])
++ hasData++;
++ }
++ }
++
++ if (hasData == 0 && del0) {
++ /* Free and return NULL */
++
++ yaffs_FreeTnode(dev, tn);
++ tn = NULL;
++ }
++
++ }
++
++ return tn;
++
++}
++
++static int yaffs_PruneFileStructure(yaffs_Device *dev,
++ yaffs_FileStructure *fStruct)
++{
++ int i;
++ int hasData;
++ int done = 0;
++ yaffs_Tnode *tn;
++
++ if (fStruct->topLevel > 0) {
++ fStruct->top =
++ yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
++
++ /* Now we have a tree with all the non-zero branches NULL but the height
++ * is the same as it was.
++ * Let's see if we can trim internal tnodes to shorten the tree.
++ * We can do this if only the 0th element in the tnode is in use
++ * (ie all the non-zero are NULL)
++ */
++
++ while (fStruct->topLevel && !done) {
++ tn = fStruct->top;
++
++ hasData = 0;
++ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
++ if (tn->internal[i])
++ hasData++;
++ }
++
++ if (!hasData) {
++ fStruct->top = tn->internal[0];
++ fStruct->topLevel--;
++ yaffs_FreeTnode(dev, tn);
++ } else {
++ done = 1;
++ }
++ }
++ }
++
++ return YAFFS_OK;
++}
++
++/*-------------------- End of File Structure functions.-------------------*/
++
++/* yaffs_CreateFreeObjects creates a bunch more objects and
++ * adds them to the object free list.
++ */
++static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
++{
++ int i;
++ yaffs_Object *newObjects;
++ yaffs_ObjectList *list;
++
++ if (nObjects < 1)
++ return YAFFS_OK;
++
++ /* make these things */
++ newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
++ list = YMALLOC(sizeof(yaffs_ObjectList));
++
++ if (!newObjects || !list) {
++ if (newObjects){
++ YFREE(newObjects);
++ newObjects = NULL;
++ }
++ if (list){
++ YFREE(list);
++ list = NULL;
++ }
++ T(YAFFS_TRACE_ALLOCATE,
++ (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ /* Hook them into the free list */
++ for (i = 0; i < nObjects - 1; i++) {
++ newObjects[i].siblings.next =
++ (struct ylist_head *)(&newObjects[i + 1]);
++ }
++
++ newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
++ dev->freeObjects = newObjects;
++ dev->nFreeObjects += nObjects;
++ dev->nObjectsCreated += nObjects;
++
++ /* Now add this bunch of Objects to a list for freeing up. */
++
++ list->objects = newObjects;
++ list->next = dev->allocatedObjectList;
++ dev->allocatedObjectList = list;
++
++ return YAFFS_OK;
++}
++
++
++/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
++static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
++{
++ yaffs_Object *tn = NULL;
++
++#ifdef VALGRIND_TEST
++ tn = YMALLOC(sizeof(yaffs_Object));
++#else
++ /* If there are none left make more */
++ if (!dev->freeObjects)
++ yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
++
++ if (dev->freeObjects) {
++ tn = dev->freeObjects;
++ dev->freeObjects =
++ (yaffs_Object *) (dev->freeObjects->siblings.next);
++ dev->nFreeObjects--;
++ }
++#endif
++ if (tn) {
++ /* Now sweeten it up... */
++
++ memset(tn, 0, sizeof(yaffs_Object));
++ tn->beingCreated = 1;
++
++ tn->myDev = dev;
++ tn->hdrChunk = 0;
++ tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
++ YINIT_LIST_HEAD(&(tn->hardLinks));
++ YINIT_LIST_HEAD(&(tn->hashLink));
++ YINIT_LIST_HEAD(&tn->siblings);
++
++
++ /* Now make the directory sane */
++ if (dev->rootDir) {
++ tn->parent = dev->rootDir;
++ ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children);
++ }
++
++ /* Add it to the lost and found directory.
++ * NB Can't put root or lostNFound in lostNFound so
++ * check if lostNFound exists first
++ */
++ if (dev->lostNFoundDir)
++ yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
++
++ tn->beingCreated = 0;
++ }
++
++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
++
++ return tn;
++}
++
++static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
++ __u32 mode)
++{
++
++ yaffs_Object *obj =
++ yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
++ if (obj) {
++ obj->fake = 1; /* it is fake so it might have no NAND presence... */
++ obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
++ obj->unlinkAllowed = 0; /* ... or unlink it */
++ obj->deleted = 0;
++ obj->unlinked = 0;
++ obj->yst_mode = mode;
++ obj->myDev = dev;
++ obj->hdrChunk = 0; /* Not a valid chunk. */
++ }
++
++ return obj;
++
++}
++
++static void yaffs_UnhashObject(yaffs_Object *tn)
++{
++ int bucket;
++ yaffs_Device *dev = tn->myDev;
++
++ /* If it is still linked into the bucket list, free from the list */
++ if (!ylist_empty(&tn->hashLink)) {
++ ylist_del_init(&tn->hashLink);
++ bucket = yaffs_HashFunction(tn->objectId);
++ dev->objectBucket[bucket].count--;
++ }
++}
++
++/* FreeObject frees up a Object and puts it back on the free list */
++static void yaffs_FreeObject(yaffs_Object *tn)
++{
++ yaffs_Device *dev = tn->myDev;
++
++ T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
++
++ if (tn->parent)
++ YBUG();
++ if (!ylist_empty(&tn->siblings))
++ YBUG();
++
++
++ if (tn->myInode) {
++ /* We're still hooked up to a cached inode.
++ * Don't delete now, but mark for later deletion
++ */
++ tn->deferedFree = 1;
++ return;
++ }
++
++ yaffs_UnhashObject(tn);
++
++#ifdef VALGRIND_TEST
++ YFREE(tn);
++ tn = NULL;
++#else
++ /* Link into the free list. */
++ tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
++ dev->freeObjects = tn;
++ dev->nFreeObjects++;
++#endif
++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
++}
++
++#ifdef __KERNEL__
++
++void yaffs_HandleDeferedFree(yaffs_Object *obj)
++{
++ if (obj->deferedFree)
++ yaffs_FreeObject(obj);
++}
++
++#endif
++
++static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
++{
++ /* Free the list of allocated Objects */
++
++ yaffs_ObjectList *tmp;
++
++ while (dev->allocatedObjectList) {
++ tmp = dev->allocatedObjectList->next;
++ YFREE(dev->allocatedObjectList->objects);
++ YFREE(dev->allocatedObjectList);
++
++ dev->allocatedObjectList = tmp;
++ }
++
++ dev->freeObjects = NULL;
++ dev->nFreeObjects = 0;
++ dev->nObjectsCreated = 0;
++}
++
++static void yaffs_InitialiseObjects(yaffs_Device *dev)
++{
++ int i;
++
++ dev->allocatedObjectList = NULL;
++ dev->freeObjects = NULL;
++ dev->nFreeObjects = 0;
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ YINIT_LIST_HEAD(&dev->objectBucket[i].list);
++ dev->objectBucket[i].count = 0;
++ }
++}
++
++static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
++{
++ static int x;
++ int i;
++ int l = 999;
++ int lowest = 999999;
++
++ /* First let's see if we can find one that's empty. */
++
++ for (i = 0; i < 10 && lowest > 0; i++) {
++ x++;
++ x %= YAFFS_NOBJECT_BUCKETS;
++ if (dev->objectBucket[x].count < lowest) {
++ lowest = dev->objectBucket[x].count;
++ l = x;
++ }
++
++ }
++
++ /* If we didn't find an empty list, then try
++ * looking a bit further for a short one
++ */
++
++ for (i = 0; i < 10 && lowest > 3; i++) {
++ x++;
++ x %= YAFFS_NOBJECT_BUCKETS;
++ if (dev->objectBucket[x].count < lowest) {
++ lowest = dev->objectBucket[x].count;
++ l = x;
++ }
++
++ }
++
++ return l;
++}
++
++static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
++{
++ int bucket = yaffs_FindNiceObjectBucket(dev);
++
++ /* Now find an object value that has not already been taken
++ * by scanning the list.
++ */
++
++ int found = 0;
++ struct ylist_head *i;
++
++ __u32 n = (__u32) bucket;
++
++ /* yaffs_CheckObjectHashSanity(); */
++
++ while (!found) {
++ found = 1;
++ n += YAFFS_NOBJECT_BUCKETS;
++ if (1 || dev->objectBucket[bucket].count > 0) {
++ ylist_for_each(i, &dev->objectBucket[bucket].list) {
++ /* If there is already one in the list */
++ if (i && ylist_entry(i, yaffs_Object,
++ hashLink)->objectId == n) {
++ found = 0;
++ }
++ }
++ }
++ }
++
++ return n;
++}
++
++static void yaffs_HashObject(yaffs_Object *in)
++{
++ int bucket = yaffs_HashFunction(in->objectId);
++ yaffs_Device *dev = in->myDev;
++
++ ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
++ dev->objectBucket[bucket].count++;
++}
++
++yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
++{
++ int bucket = yaffs_HashFunction(number);
++ struct ylist_head *i;
++ yaffs_Object *in;
++
++ ylist_for_each(i, &dev->objectBucket[bucket].list) {
++ /* Look if it is in the list */
++ if (i) {
++ in = ylist_entry(i, yaffs_Object, hashLink);
++ if (in->objectId == number) {
++#ifdef __KERNEL__
++ /* Don't tell the VFS about this one if it is defered free */
++ if (in->deferedFree)
++ return NULL;
++#endif
++
++ return in;
++ }
++ }
++ }
++
++ return NULL;
++}
++
++yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
++ yaffs_ObjectType type)
++{
++ yaffs_Object *theObject;
++ yaffs_Tnode *tn = NULL;
++
++ if (number < 0)
++ number = yaffs_CreateNewObjectNumber(dev);
++
++ if (type == YAFFS_OBJECT_TYPE_FILE) {
++ tn = yaffs_GetTnode(dev);
++ if (!tn)
++ return NULL;
++ }
++
++ theObject = yaffs_AllocateEmptyObject(dev);
++ if (!theObject){
++ if(tn)
++ yaffs_FreeTnode(dev,tn);
++ return NULL;
++ }
++
++
++ if (theObject) {
++ theObject->fake = 0;
++ theObject->renameAllowed = 1;
++ theObject->unlinkAllowed = 1;
++ theObject->objectId = number;
++ yaffs_HashObject(theObject);
++ theObject->variantType = type;
++#ifdef CONFIG_YAFFS_WINCE
++ yfsd_WinFileTimeNow(theObject->win_atime);
++ theObject->win_ctime[0] = theObject->win_mtime[0] =
++ theObject->win_atime[0];
++ theObject->win_ctime[1] = theObject->win_mtime[1] =
++ theObject->win_atime[1];
++
++#else
++
++ theObject->yst_atime = theObject->yst_mtime =
++ theObject->yst_ctime = Y_CURRENT_TIME;
++#endif
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ theObject->variant.fileVariant.fileSize = 0;
++ theObject->variant.fileVariant.scannedFileSize = 0;
++ theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
++ theObject->variant.fileVariant.topLevel = 0;
++ theObject->variant.fileVariant.top = tn;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
++ children);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* No action required */
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* todo this should not happen */
++ break;
++ }
++ }
++
++ return theObject;
++}
++
++static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
++ int number,
++ yaffs_ObjectType type)
++{
++ yaffs_Object *theObject = NULL;
++
++ if (number > 0)
++ theObject = yaffs_FindObjectByNumber(dev, number);
++
++ if (!theObject)
++ theObject = yaffs_CreateNewObject(dev, number, type);
++
++ return theObject;
++
++}
++
++
++static YCHAR *yaffs_CloneString(const YCHAR *str)
++{
++ YCHAR *newStr = NULL;
++ int len;
++
++ if (!str)
++ str = _Y("");
++
++ len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH);
++ newStr = YMALLOC((len + 1) * sizeof(YCHAR));
++ if (newStr){
++ yaffs_strncpy(newStr, str,len);
++ newStr[len] = 0;
++ }
++ return newStr;
++
++}
++
++/*
++ * Mknod (create) a new object.
++ * equivalentObject only has meaning for a hard link;
++ * aliasString only has meaning for a symlink.
++ * rdev only has meaning for devices (a subset of special objects)
++ */
++
++static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
++ yaffs_Object *parent,
++ const YCHAR *name,
++ __u32 mode,
++ __u32 uid,
++ __u32 gid,
++ yaffs_Object *equivalentObject,
++ const YCHAR *aliasString, __u32 rdev)
++{
++ yaffs_Object *in;
++ YCHAR *str = NULL;
++
++ yaffs_Device *dev = parent->myDev;
++
++ /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
++ if (yaffs_FindObjectByName(parent, name))
++ return NULL;
++
++ if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
++ str = yaffs_CloneString(aliasString);
++ if (!str)
++ return NULL;
++ }
++
++ in = yaffs_CreateNewObject(dev, -1, type);
++
++ if (!in){
++ if(str)
++ YFREE(str);
++ return NULL;
++ }
++
++
++
++
++ if (in) {
++ in->hdrChunk = 0;
++ in->valid = 1;
++ in->variantType = type;
++
++ in->yst_mode = mode;
++
++#ifdef CONFIG_YAFFS_WINCE
++ yfsd_WinFileTimeNow(in->win_atime);
++ in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
++ in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
++
++#else
++ in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
++
++ in->yst_rdev = rdev;
++ in->yst_uid = uid;
++ in->yst_gid = gid;
++#endif
++ in->nDataChunks = 0;
++
++ yaffs_SetObjectName(in, name);
++ in->dirty = 1;
++
++ yaffs_AddObjectToDirectory(parent, in);
++
++ in->myDev = parent->myDev;
++
++ switch (type) {
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ in->variant.symLinkVariant.alias = str;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ in->variant.hardLinkVariant.equivalentObject =
++ equivalentObject;
++ in->variant.hardLinkVariant.equivalentObjectId =
++ equivalentObject->objectId;
++ ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* do nothing */
++ break;
++ }
++
++ if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
++ /* Could not create the object header, fail the creation */
++ yaffs_DeleteObject(in);
++ in = NULL;
++ }
++
++ yaffs_UpdateParent(parent);
++ }
++
++ return in;
++}
++
++yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
++ __u32 mode, __u32 uid, __u32 gid)
++{
++ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
++ uid, gid, NULL, NULL, 0);
++}
++
++yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
++ __u32 mode, __u32 uid, __u32 gid)
++{
++ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
++ mode, uid, gid, NULL, NULL, 0);
++}
++
++yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
++ __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
++{
++ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
++ uid, gid, NULL, NULL, rdev);
++}
++
++yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
++ __u32 mode, __u32 uid, __u32 gid,
++ const YCHAR *alias)
++{
++ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
++ uid, gid, NULL, alias, 0);
++}
++
++/* yaffs_Link returns the object id of the equivalent object.*/
++yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
++ yaffs_Object *equivalentObject)
++{
++ /* Get the real object in case we were fed a hard link as an equivalent object */
++ equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
++
++ if (yaffs_MknodObject
++ (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
++ equivalentObject, NULL, 0)) {
++ return equivalentObject;
++ } else {
++ return NULL;
++ }
++
++}
++
++static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
++ const YCHAR *newName, int force, int shadows)
++{
++ int unlinkOp;
++ int deleteOp;
++
++ yaffs_Object *existingTarget;
++
++ if (newDir == NULL)
++ newDir = obj->parent; /* use the old directory */
++
++ if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
++ TENDSTR)));
++ YBUG();
++ }
++
++ /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
++ if (obj->myDev->isYaffs2)
++ unlinkOp = (newDir == obj->myDev->unlinkedDir);
++ else
++ unlinkOp = (newDir == obj->myDev->unlinkedDir
++ && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
++
++ deleteOp = (newDir == obj->myDev->deletedDir);
++
++ existingTarget = yaffs_FindObjectByName(newDir, newName);
++
++ /* If the object is a file going into the unlinked directory,
++ * then it is OK to just stuff it in since duplicate names are allowed.
++ * else only proceed if the new name does not exist and if we're putting
++ * it into a directory.
++ */
++ if ((unlinkOp ||
++ deleteOp ||
++ force ||
++ (shadows > 0) ||
++ !existingTarget) &&
++ newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
++ yaffs_SetObjectName(obj, newName);
++ obj->dirty = 1;
++
++ yaffs_AddObjectToDirectory(newDir, obj);
++
++ if (unlinkOp)
++ obj->unlinked = 1;
++
++ /* If it is a deletion then we mark it as a shrink for gc purposes. */
++ if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0)
++ return YAFFS_OK;
++ }
++
++ return YAFFS_FAIL;
++}
++
++int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
++ yaffs_Object *newDir, const YCHAR *newName)
++{
++ yaffs_Object *obj = NULL;
++ yaffs_Object *existingTarget = NULL;
++ int force = 0;
++ int result;
++ yaffs_Device *dev;
++
++
++ if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
++ YBUG();
++ if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
++ YBUG();
++
++ dev = oldDir->myDev;
++
++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
++ /* Special case for case insemsitive systems (eg. WinCE).
++ * While look-up is case insensitive, the name isn't.
++ * Therefore we might want to change x.txt to X.txt
++ */
++ if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
++ force = 1;
++#endif
++
++ if(yaffs_strnlen(newName,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH)
++ /* ENAMETOOLONG */
++ return YAFFS_FAIL;
++
++ obj = yaffs_FindObjectByName(oldDir, oldName);
++
++ if (obj && obj->renameAllowed) {
++
++ /* Now do the handling for an existing target, if there is one */
++
++ existingTarget = yaffs_FindObjectByName(newDir, newName);
++ if (existingTarget &&
++ existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
++ !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
++ /* There is a target that is a non-empty directory, so we fail */
++ return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
++ } else if (existingTarget && existingTarget != obj) {
++ /* Nuke the target first, using shadowing,
++ * but only if it isn't the same object.
++ *
++ * Note we must disable gc otherwise it can mess up the shadowing.
++ *
++ */
++ dev->isDoingGC=1;
++ yaffs_ChangeObjectName(obj, newDir, newName, force,
++ existingTarget->objectId);
++ existingTarget->isShadowed = 1;
++ yaffs_UnlinkObject(existingTarget);
++ dev->isDoingGC=0;
++ }
++
++ result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
++
++ yaffs_UpdateParent(oldDir);
++ if(newDir != oldDir)
++ yaffs_UpdateParent(newDir);
++
++ return result;
++ }
++ return YAFFS_FAIL;
++}
++
++/*------------------------- Block Management and Page Allocation ----------------*/
++
++static int yaffs_InitialiseBlocks(yaffs_Device *dev)
++{
++ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
++
++ dev->blockInfo = NULL;
++ dev->chunkBits = NULL;
++
++ dev->allocationBlock = -1; /* force it to get a new one */
++
++ /* If the first allocation strategy fails, thry the alternate one */
++ dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
++ if (!dev->blockInfo) {
++ dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
++ dev->blockInfoAlt = 1;
++ } else
++ dev->blockInfoAlt = 0;
++
++ if (dev->blockInfo) {
++ /* Set up dynamic blockinfo stuff. */
++ dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
++ dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
++ if (!dev->chunkBits) {
++ dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
++ dev->chunkBitsAlt = 1;
++ } else
++ dev->chunkBitsAlt = 0;
++ }
++
++ if (dev->blockInfo && dev->chunkBits) {
++ memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
++ memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
++ return YAFFS_OK;
++ }
++
++ return YAFFS_FAIL;
++}
++
++static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
++{
++ if (dev->blockInfoAlt && dev->blockInfo)
++ YFREE_ALT(dev->blockInfo);
++ else if (dev->blockInfo)
++ YFREE(dev->blockInfo);
++
++ dev->blockInfoAlt = 0;
++
++ dev->blockInfo = NULL;
++
++ if (dev->chunkBitsAlt && dev->chunkBits)
++ YFREE_ALT(dev->chunkBits);
++ else if (dev->chunkBits)
++ YFREE(dev->chunkBits);
++ dev->chunkBitsAlt = 0;
++ dev->chunkBits = NULL;
++}
++
++static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
++ yaffs_BlockInfo *bi)
++{
++ int i;
++ __u32 seq;
++ yaffs_BlockInfo *b;
++
++ if (!dev->isYaffs2)
++ return 1; /* disqualification only applies to yaffs2. */
++
++ if (!bi->hasShrinkHeader)
++ return 1; /* can gc */
++
++ /* Find the oldest dirty sequence number if we don't know it and save it
++ * so we don't have to keep recomputing it.
++ */
++ if (!dev->oldestDirtySequence) {
++ seq = dev->sequenceNumber;
++
++ for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
++ i++) {
++ b = yaffs_GetBlockInfo(dev, i);
++ if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
++ (b->pagesInUse - b->softDeletions) <
++ dev->nChunksPerBlock && b->sequenceNumber < seq) {
++ seq = b->sequenceNumber;
++ }
++ }
++ dev->oldestDirtySequence = seq;
++ }
++
++ /* Can't do gc of this block if there are any blocks older than this one that have
++ * discarded pages.
++ */
++ return (bi->sequenceNumber <= dev->oldestDirtySequence);
++}
++
++/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
++ * for garbage collection.
++ */
++
++static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
++ int aggressive)
++{
++ int b = dev->currentDirtyChecker;
++
++ int i;
++ int iterations;
++ int dirtiest = -1;
++ int pagesInUse = 0;
++ int prioritised = 0;
++ yaffs_BlockInfo *bi;
++ int pendingPrioritisedExist = 0;
++
++ /* First let's see if we need to grab a prioritised block */
++ if (dev->hasPendingPrioritisedGCs) {
++ for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) {
++
++ bi = yaffs_GetBlockInfo(dev, i);
++ /* yaffs_VerifyBlock(dev,bi,i); */
++
++ if (bi->gcPrioritise) {
++ pendingPrioritisedExist = 1;
++ if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
++ yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
++ pagesInUse = (bi->pagesInUse - bi->softDeletions);
++ dirtiest = i;
++ prioritised = 1;
++ aggressive = 1; /* Fool the non-aggressive skip logiv below */
++ }
++ }
++ }
++
++ if (!pendingPrioritisedExist) /* None found, so we can clear this */
++ dev->hasPendingPrioritisedGCs = 0;
++ }
++
++ /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
++ * search harder.
++ * else (we're doing a leasurely gc), then we only bother to do this if the
++ * block has only a few pages in use.
++ */
++
++ dev->nonAggressiveSkip--;
++
++ if (!aggressive && (dev->nonAggressiveSkip > 0))
++ return -1;
++
++ if (!prioritised)
++ pagesInUse =
++ (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
++
++ if (aggressive)
++ iterations =
++ dev->internalEndBlock - dev->internalStartBlock + 1;
++ else {
++ iterations =
++ dev->internalEndBlock - dev->internalStartBlock + 1;
++ iterations = iterations / 16;
++ if (iterations > 200)
++ iterations = 200;
++ }
++
++ for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
++ b++;
++ if (b < dev->internalStartBlock || b > dev->internalEndBlock)
++ b = dev->internalStartBlock;
++
++ if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("**>> Block %d is not valid" TENDSTR), b));
++ YBUG();
++ }
++
++ bi = yaffs_GetBlockInfo(dev, b);
++
++ if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
++ (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
++ yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
++ dirtiest = b;
++ pagesInUse = (bi->pagesInUse - bi->softDeletions);
++ }
++ }
++
++ dev->currentDirtyChecker = b;
++
++ if (dirtiest > 0) {
++ T(YAFFS_TRACE_GC,
++ (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
++ dev->nChunksPerBlock - pagesInUse, prioritised));
++ }
++
++ dev->oldestDirtySequence = 0;
++
++ if (dirtiest > 0)
++ dev->nonAggressiveSkip = 4;
++
++ return dirtiest;
++}
++
++static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
++{
++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
++
++ int erasedOk = 0;
++
++ /* If the block is still healthy erase it and mark as clean.
++ * If the block has had a data failure, then retire it.
++ */
++
++ T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
++ (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
++ blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
++
++ bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
++
++ if (!bi->needsRetiring) {
++ yaffs_InvalidateCheckpoint(dev);
++ erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
++ if (!erasedOk) {
++ dev->nErasureFailures++;
++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
++ }
++ }
++
++ if (erasedOk &&
++ ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
++ int i;
++ for (i = 0; i < dev->nChunksPerBlock; i++) {
++ if (!yaffs_CheckChunkErased
++ (dev, blockNo * dev->nChunksPerBlock + i)) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ (">>Block %d erasure supposedly OK, but chunk %d not erased"
++ TENDSTR), blockNo, i));
++ }
++ }
++ }
++
++ if (erasedOk) {
++ /* Clean it up... */
++ bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
++ dev->nErasedBlocks++;
++ bi->pagesInUse = 0;
++ bi->softDeletions = 0;
++ bi->hasShrinkHeader = 0;
++ bi->skipErasedCheck = 1; /* This is clean, so no need to check */
++ bi->gcPrioritise = 0;
++ yaffs_ClearChunkBits(dev, blockNo);
++
++ T(YAFFS_TRACE_ERASE,
++ (TSTR("Erased block %d" TENDSTR), blockNo));
++ } else {
++ dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */
++
++ yaffs_RetireBlock(dev, blockNo);
++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("**>> Block %d retired" TENDSTR), blockNo));
++ }
++}
++
++static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
++{
++ int i;
++
++ yaffs_BlockInfo *bi;
++
++ if (dev->nErasedBlocks < 1) {
++ /* Hoosterman we've got a problem.
++ * Can't get space to gc
++ */
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
++
++ return -1;
++ }
++
++ /* Find an empty block. */
++
++ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
++ dev->allocationBlockFinder++;
++ if (dev->allocationBlockFinder < dev->internalStartBlock
++ || dev->allocationBlockFinder > dev->internalEndBlock) {
++ dev->allocationBlockFinder = dev->internalStartBlock;
++ }
++
++ bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
++
++ if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
++ bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->sequenceNumber++;
++ bi->sequenceNumber = dev->sequenceNumber;
++ dev->nErasedBlocks--;
++ T(YAFFS_TRACE_ALLOCATE,
++ (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
++ dev->allocationBlockFinder, dev->sequenceNumber,
++ dev->nErasedBlocks));
++ return dev->allocationBlockFinder;
++ }
++ }
++
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("yaffs tragedy: no more erased blocks, but there should have been %d"
++ TENDSTR), dev->nErasedBlocks));
++
++ return -1;
++}
++
++
++
++static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
++{
++ if (!dev->nCheckpointBlocksRequired &&
++ dev->isYaffs2) {
++ /* Not a valid value so recalculate */
++ int nBytes = 0;
++ int nBlocks;
++ int devBlocks = (dev->endBlock - dev->startBlock + 1);
++ int tnodeSize;
++
++ tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
++
++ if (tnodeSize < sizeof(yaffs_Tnode))
++ tnodeSize = sizeof(yaffs_Tnode);
++
++ nBytes += sizeof(yaffs_CheckpointValidity);
++ nBytes += sizeof(yaffs_CheckpointDevice);
++ nBytes += devBlocks * sizeof(yaffs_BlockInfo);
++ nBytes += devBlocks * dev->chunkBitmapStride;
++ nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);
++ nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);
++ nBytes += sizeof(yaffs_CheckpointValidity);
++ nBytes += sizeof(__u32); /* checksum*/
++
++ /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
++
++ nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3;
++
++ dev->nCheckpointBlocksRequired = nBlocks;
++ }
++
++ return dev->nCheckpointBlocksRequired;
++}
++
++/*
++ * Check if there's space to allocate...
++ * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
++ */
++static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
++{
++ int reservedChunks;
++ int reservedBlocks = dev->nReservedBlocks;
++ int checkpointBlocks;
++
++ if (dev->isYaffs2) {
++ checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) -
++ dev->blocksInCheckpoint;
++ if (checkpointBlocks < 0)
++ checkpointBlocks = 0;
++ } else {
++ checkpointBlocks = 0;
++ }
++
++ reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
++
++ return (dev->nFreeChunks > reservedChunks);
++}
++
++static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
++ yaffs_BlockInfo **blockUsedPtr)
++{
++ int retVal;
++ yaffs_BlockInfo *bi;
++
++ if (dev->allocationBlock < 0) {
++ /* Get next block to allocate off */
++ dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
++ dev->allocationPage = 0;
++ }
++
++ if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
++ /* Not enough space to allocate unless we're allowed to use the reserve. */
++ return -1;
++ }
++
++ if (dev->nErasedBlocks < dev->nReservedBlocks
++ && dev->allocationPage == 0) {
++ T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
++ }
++
++ /* Next page please.... */
++ if (dev->allocationBlock >= 0) {
++ bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
++
++ retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
++ dev->allocationPage;
++ bi->pagesInUse++;
++ yaffs_SetChunkBit(dev, dev->allocationBlock,
++ dev->allocationPage);
++
++ dev->allocationPage++;
++
++ dev->nFreeChunks--;
++
++ /* If the block is full set the state to full */
++ if (dev->allocationPage >= dev->nChunksPerBlock) {
++ bi->blockState = YAFFS_BLOCK_STATE_FULL;
++ dev->allocationBlock = -1;
++ }
++
++ if (blockUsedPtr)
++ *blockUsedPtr = bi;
++
++ return retVal;
++ }
++
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
++
++ return -1;
++}
++
++static int yaffs_GetErasedChunks(yaffs_Device *dev)
++{
++ int n;
++
++ n = dev->nErasedBlocks * dev->nChunksPerBlock;
++
++ if (dev->allocationBlock > 0)
++ n += (dev->nChunksPerBlock - dev->allocationPage);
++
++ return n;
++
++}
++
++/*
++ * yaffs_SkipRestOfBlock() skips over the rest of the allocation block
++ * if we don't want to write to it.
++ */
++static void yaffs_SkipRestOfBlock(yaffs_Device *dev)
++{
++ if(dev->allocationBlock > 0){
++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
++ if(bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING){
++ bi->blockState = YAFFS_BLOCK_STATE_FULL;
++ dev->allocationBlock = -1;
++ }
++ }
++}
++
++
++static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
++ int wholeBlock)
++{
++ int oldChunk;
++ int newChunk;
++ int markNAND;
++ int retVal = YAFFS_OK;
++ int cleanups = 0;
++ int i;
++ int isCheckpointBlock;
++ int matchingChunk;
++ int maxCopies;
++
++ int chunksBefore = yaffs_GetErasedChunks(dev);
++ int chunksAfter;
++
++ yaffs_ExtendedTags tags;
++
++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
++
++ yaffs_Object *object;
++
++ isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
++
++
++ T(YAFFS_TRACE_TRACING,
++ (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
++ block,
++ bi->pagesInUse,
++ bi->hasShrinkHeader,
++ wholeBlock));
++
++ /*yaffs_VerifyFreeChunks(dev); */
++
++ if(bi->blockState == YAFFS_BLOCK_STATE_FULL)
++ bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
++
++ bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
++
++ /* Take off the number of soft deleted entries because
++ * they're going to get really deleted during GC.
++ */
++ if(dev->gcChunk == 0) /* first time through for this block */
++ dev->nFreeChunks -= bi->softDeletions;
++
++ dev->isDoingGC = 1;
++
++ if (isCheckpointBlock ||
++ !yaffs_StillSomeChunkBits(dev, block)) {
++ T(YAFFS_TRACE_TRACING,
++ (TSTR
++ ("Collecting block %d that has no chunks in use" TENDSTR),
++ block));
++ yaffs_BlockBecameDirty(dev, block);
++ } else {
++
++ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
++
++ yaffs_VerifyBlock(dev, bi, block);
++
++ maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10;
++ oldChunk = block * dev->nChunksPerBlock + dev->gcChunk;
++
++ for (/* init already done */;
++ retVal == YAFFS_OK &&
++ dev->gcChunk < dev->nChunksPerBlock &&
++ (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
++ maxCopies > 0;
++ dev->gcChunk++, oldChunk++) {
++ if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
++
++ /* This page is in use and might need to be copied off */
++
++ maxCopies--;
++
++ markNAND = 1;
++
++ yaffs_InitialiseTags(&tags);
++
++ yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
++ buffer, &tags);
++
++ object =
++ yaffs_FindObjectByNumber(dev,
++ tags.objectId);
++
++ T(YAFFS_TRACE_GC_DETAIL,
++ (TSTR
++ ("Collecting chunk in block %d, %d %d %d " TENDSTR),
++ dev->gcChunk, tags.objectId, tags.chunkId,
++ tags.byteCount));
++
++ if (object && !yaffs_SkipVerification(dev)) {
++ if (tags.chunkId == 0)
++ matchingChunk = object->hdrChunk;
++ else if (object->softDeleted)
++ matchingChunk = oldChunk; /* Defeat the test */
++ else
++ matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
++
++ if (oldChunk != matchingChunk)
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
++ oldChunk, matchingChunk, tags.objectId, tags.chunkId));
++
++ }
++
++ if (!object) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("page %d in gc has no object: %d %d %d "
++ TENDSTR), oldChunk,
++ tags.objectId, tags.chunkId, tags.byteCount));
++ }
++
++ if (object &&
++ object->deleted &&
++ object->softDeleted &&
++ tags.chunkId != 0) {
++ /* Data chunk in a soft deleted file, throw it away
++ * It's a soft deleted data chunk,
++ * No need to copy this, just forget about it and
++ * fix up the object.
++ */
++
++ object->nDataChunks--;
++
++ if (object->nDataChunks <= 0) {
++ /* remeber to clean up the object */
++ dev->gcCleanupList[cleanups] =
++ tags.objectId;
++ cleanups++;
++ }
++ markNAND = 0;
++ } else if (0) {
++ /* Todo object && object->deleted && object->nDataChunks == 0 */
++ /* Deleted object header with no data chunks.
++ * Can be discarded and the file deleted.
++ */
++ object->hdrChunk = 0;
++ yaffs_FreeTnode(object->myDev,
++ object->variant.
++ fileVariant.top);
++ object->variant.fileVariant.top = NULL;
++ yaffs_DoGenericObjectDeletion(object);
++
++ } else if (object) {
++ /* It's either a data chunk in a live file or
++ * an ObjectHeader, so we're interested in it.
++ * NB Need to keep the ObjectHeaders of deleted files
++ * until the whole file has been deleted off
++ */
++ tags.serialNumber++;
++
++ dev->nGCCopies++;
++
++ if (tags.chunkId == 0) {
++ /* It is an object Id,
++ * We need to nuke the shrinkheader flags first
++ * Also need to clean up shadowing.
++ * We no longer want the shrinkHeader flag since its work is done
++ * and if it is left in place it will mess up scanning.
++ */
++
++ yaffs_ObjectHeader *oh;
++ oh = (yaffs_ObjectHeader *)buffer;
++ oh->isShrink = 0;
++ tags.extraIsShrinkHeader = 0;
++ oh->shadowsObject = 0;
++ oh->inbandShadowsObject = 0;
++ tags.extraShadows = 0;
++
++ yaffs_VerifyObjectHeader(object, oh, &tags, 1);
++ }
++
++ newChunk =
++ yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
++
++ if (newChunk < 0) {
++ retVal = YAFFS_FAIL;
++ } else {
++
++ /* Ok, now fix up the Tnodes etc. */
++
++ if (tags.chunkId == 0) {
++ /* It's a header */
++ object->hdrChunk = newChunk;
++ object->serial = tags.serialNumber;
++ } else {
++ /* It's a data chunk */
++ yaffs_PutChunkIntoFile
++ (object,
++ tags.chunkId,
++ newChunk, 0);
++ }
++ }
++ }
++
++ if (retVal == YAFFS_OK)
++ yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
++
++ }
++ }
++
++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
++
++
++ /* Do any required cleanups */
++ for (i = 0; i < cleanups; i++) {
++ /* Time to delete the file too */
++ object =
++ yaffs_FindObjectByNumber(dev,
++ dev->gcCleanupList[i]);
++ if (object) {
++ yaffs_FreeTnode(dev,
++ object->variant.fileVariant.
++ top);
++ object->variant.fileVariant.top = NULL;
++ T(YAFFS_TRACE_GC,
++ (TSTR
++ ("yaffs: About to finally delete object %d"
++ TENDSTR), object->objectId));
++ yaffs_DoGenericObjectDeletion(object);
++ object->myDev->nDeletedFiles--;
++ }
++
++ }
++
++ }
++
++ yaffs_VerifyCollectedBlock(dev, bi, block);
++
++ chunksAfter = yaffs_GetErasedChunks(dev);
++ if (chunksBefore >= chunksAfter) {
++ T(YAFFS_TRACE_GC,
++ (TSTR
++ ("gc did not increase free chunks before %d after %d"
++ TENDSTR), chunksBefore, chunksAfter));
++ }
++
++ /* If the gc completed then clear the current gcBlock so that we find another. */
++ if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
++ dev->gcBlock = -1;
++ dev->gcChunk = 0;
++ }
++
++ dev->isDoingGC = 0;
++
++ return retVal;
++}
++
++/* New garbage collector
++ * If we're very low on erased blocks then we do aggressive garbage collection
++ * otherwise we do "leasurely" garbage collection.
++ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
++ * Passive gc only inspects smaller areas and will only accept more dirty blocks.
++ *
++ * The idea is to help clear out space in a more spread-out manner.
++ * Dunno if it really does anything useful.
++ */
++static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
++{
++ int block;
++ int aggressive;
++ int gcOk = YAFFS_OK;
++ int maxTries = 0;
++
++ int checkpointBlockAdjust;
++
++ if (dev->isDoingGC) {
++ /* Bail out so we don't get recursive gc */
++ return YAFFS_OK;
++ }
++
++ /* This loop should pass the first time.
++ * We'll only see looping here if the erase of the collected block fails.
++ */
++
++ do {
++ maxTries++;
++
++ checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
++ if (checkpointBlockAdjust < 0)
++ checkpointBlockAdjust = 0;
++
++ if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
++ /* We need a block soon...*/
++ aggressive = 1;
++ } else {
++ /* We're in no hurry */
++ aggressive = 0;
++ }
++
++ if (dev->gcBlock <= 0) {
++ dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
++ dev->gcChunk = 0;
++ }
++
++ block = dev->gcBlock;
++
++ if (block > 0) {
++ dev->garbageCollections++;
++ if (!aggressive)
++ dev->passiveGarbageCollections++;
++
++ T(YAFFS_TRACE_GC,
++ (TSTR
++ ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
++ dev->nErasedBlocks, aggressive));
++
++ gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive);
++ }
++
++ if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
++ T(YAFFS_TRACE_GC,
++ (TSTR
++ ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
++ TENDSTR), dev->nErasedBlocks, maxTries, block));
++ }
++ } while ((dev->nErasedBlocks < dev->nReservedBlocks) &&
++ (block > 0) &&
++ (maxTries < 2));
++
++ return aggressive ? gcOk : YAFFS_OK;
++}
++
++/*------------------------- TAGS --------------------------------*/
++
++static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
++ int chunkInObject)
++{
++ return (tags->chunkId == chunkInObject &&
++ tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
++
++}
++
++
++/*-------------------- Data file manipulation -----------------*/
++
++static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
++ yaffs_ExtendedTags *tags)
++{
++ /*Get the Tnode, then get the level 0 offset chunk offset */
++ yaffs_Tnode *tn;
++ int theChunk = -1;
++ yaffs_ExtendedTags localTags;
++ int retVal = -1;
++
++ yaffs_Device *dev = in->myDev;
++
++ if (!tags) {
++ /* Passed a NULL, so use our own tags space */
++ tags = &localTags;
++ }
++
++ tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
++
++ if (tn) {
++ theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
++
++ retVal =
++ yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
++ chunkInInode);
++ }
++ return retVal;
++}
++
++static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
++ yaffs_ExtendedTags *tags)
++{
++ /* Get the Tnode, then get the level 0 offset chunk offset */
++ yaffs_Tnode *tn;
++ int theChunk = -1;
++ yaffs_ExtendedTags localTags;
++
++ yaffs_Device *dev = in->myDev;
++ int retVal = -1;
++
++ if (!tags) {
++ /* Passed a NULL, so use our own tags space */
++ tags = &localTags;
++ }
++
++ tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
++
++ if (tn) {
++
++ theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
++
++ retVal =
++ yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
++ chunkInInode);
++
++ /* Delete the entry in the filestructure (if found) */
++ if (retVal != -1)
++ yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, 0);
++ }
++
++ return retVal;
++}
++
++#ifdef YAFFS_PARANOID
++
++static int yaffs_CheckFileSanity(yaffs_Object *in)
++{
++ int chunk;
++ int nChunks;
++ int fSize;
++ int failed = 0;
++ int objId;
++ yaffs_Tnode *tn;
++ yaffs_Tags localTags;
++ yaffs_Tags *tags = &localTags;
++ int theChunk;
++ int chunkDeleted;
++
++ if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
++ return YAFFS_FAIL;
++
++ objId = in->objectId;
++ fSize = in->variant.fileVariant.fileSize;
++ nChunks =
++ (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
++
++ for (chunk = 1; chunk <= nChunks; chunk++) {
++ tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
++ chunk);
++
++ if (tn) {
++
++ theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
++
++ if (yaffs_CheckChunkBits
++ (dev, theChunk / dev->nChunksPerBlock,
++ theChunk % dev->nChunksPerBlock)) {
++
++ yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
++ tags,
++ &chunkDeleted);
++ if (yaffs_TagsMatch
++ (tags, in->objectId, chunk, chunkDeleted)) {
++ /* found it; */
++
++ }
++ } else {
++
++ failed = 1;
++ }
++
++ } else {
++ /* T(("No level 0 found for %d\n", chunk)); */
++ }
++ }
++
++ return failed ? YAFFS_FAIL : YAFFS_OK;
++}
++
++#endif
++
++static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
++ int chunkInNAND, int inScan)
++{
++ /* NB inScan is zero unless scanning.
++ * For forward scanning, inScan is > 0;
++ * for backward scanning inScan is < 0
++ *
++ * chunkInNAND = 0 is a dummy insert to make sure the tnodes are there.
++ */
++
++ yaffs_Tnode *tn;
++ yaffs_Device *dev = in->myDev;
++ int existingChunk;
++ yaffs_ExtendedTags existingTags;
++ yaffs_ExtendedTags newTags;
++ unsigned existingSerial, newSerial;
++
++ if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
++ /* Just ignore an attempt at putting a chunk into a non-file during scanning
++ * If it is not during Scanning then something went wrong!
++ */
++ if (!inScan) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs tragedy:attempt to put data chunk into a non-file"
++ TENDSTR)));
++ YBUG();
++ }
++
++ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
++ return YAFFS_OK;
++ }
++
++ tn = yaffs_AddOrFindLevel0Tnode(dev,
++ &in->variant.fileVariant,
++ chunkInInode,
++ NULL);
++ if (!tn)
++ return YAFFS_FAIL;
++
++ if(!chunkInNAND)
++ /* Dummy insert, bail now */
++ return YAFFS_OK;
++
++
++ existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
++
++ if (inScan != 0) {
++ /* If we're scanning then we need to test for duplicates
++ * NB This does not need to be efficient since it should only ever
++ * happen when the power fails during a write, then only one
++ * chunk should ever be affected.
++ *
++ * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
++ * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
++ */
++
++ if (existingChunk > 0) {
++ /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
++ * thus we have to do a FindChunkInFile to get the real chunk id.
++ *
++ * We have a duplicate now we need to decide which one to use:
++ *
++ * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
++ * Forward scanning YAFFS2: The new one is what we use, dump the old one.
++ * YAFFS1: Get both sets of tags and compare serial numbers.
++ */
++
++ if (inScan > 0) {
++ /* Only do this for forward scanning */
++ yaffs_ReadChunkWithTagsFromNAND(dev,
++ chunkInNAND,
++ NULL, &newTags);
++
++ /* Do a proper find */
++ existingChunk =
++ yaffs_FindChunkInFile(in, chunkInInode,
++ &existingTags);
++ }
++
++ if (existingChunk <= 0) {
++ /*Hoosterman - how did this happen? */
++
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs tragedy: existing chunk < 0 in scan"
++ TENDSTR)));
++
++ }
++
++ /* NB The deleted flags should be false, otherwise the chunks will
++ * not be loaded during a scan
++ */
++
++ if (inScan > 0) {
++ newSerial = newTags.serialNumber;
++ existingSerial = existingTags.serialNumber;
++ }
++
++ if ((inScan > 0) &&
++ (in->myDev->isYaffs2 ||
++ existingChunk <= 0 ||
++ ((existingSerial + 1) & 3) == newSerial)) {
++ /* Forward scanning.
++ * Use new
++ * Delete the old one and drop through to update the tnode
++ */
++ yaffs_DeleteChunk(dev, existingChunk, 1,
++ __LINE__);
++ } else {
++ /* Backward scanning or we want to use the existing one
++ * Use existing.
++ * Delete the new one and return early so that the tnode isn't changed
++ */
++ yaffs_DeleteChunk(dev, chunkInNAND, 1,
++ __LINE__);
++ return YAFFS_OK;
++ }
++ }
++
++ }
++
++ if (existingChunk == 0)
++ in->nDataChunks++;
++
++ yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
++
++ return YAFFS_OK;
++}
++
++static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
++ __u8 *buffer)
++{
++ int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
++
++ if (chunkInNAND >= 0)
++ return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
++ buffer, NULL);
++ else {
++ T(YAFFS_TRACE_NANDACCESS,
++ (TSTR("Chunk %d not found zero instead" TENDSTR),
++ chunkInNAND));
++ /* get sane (zero) data if you read a hole */
++ memset(buffer, 0, in->myDev->nDataBytesPerChunk);
++ return 0;
++ }
++
++}
++
++void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
++{
++ int block;
++ int page;
++ yaffs_ExtendedTags tags;
++ yaffs_BlockInfo *bi;
++
++ if (chunkId <= 0)
++ return;
++
++ dev->nDeletions++;
++ block = chunkId / dev->nChunksPerBlock;
++ page = chunkId % dev->nChunksPerBlock;
++
++
++ if (!yaffs_CheckChunkBit(dev, block, page))
++ T(YAFFS_TRACE_VERIFY,
++ (TSTR("Deleting invalid chunk %d"TENDSTR),
++ chunkId));
++
++ bi = yaffs_GetBlockInfo(dev, block);
++
++ T(YAFFS_TRACE_DELETION,
++ (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
++
++ if (markNAND &&
++ bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
++
++ yaffs_InitialiseTags(&tags);
++
++ tags.chunkDeleted = 1;
++
++ yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
++ yaffs_HandleUpdateChunk(dev, chunkId, &tags);
++ } else {
++ dev->nUnmarkedDeletions++;
++ }
++
++ /* Pull out of the management area.
++ * If the whole block became dirty, this will kick off an erasure.
++ */
++ if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
++ bi->blockState == YAFFS_BLOCK_STATE_FULL ||
++ bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
++ bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
++ dev->nFreeChunks++;
++
++ yaffs_ClearChunkBit(dev, block, page);
++
++ bi->pagesInUse--;
++
++ if (bi->pagesInUse == 0 &&
++ !bi->hasShrinkHeader &&
++ bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
++ bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
++ yaffs_BlockBecameDirty(dev, block);
++ }
++
++ }
++
++}
++
++static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
++ const __u8 *buffer, int nBytes,
++ int useReserve)
++{
++ /* Find old chunk Need to do this to get serial number
++ * Write new one and patch into tree.
++ * Invalidate old tags.
++ */
++
++ int prevChunkId;
++ yaffs_ExtendedTags prevTags;
++
++ int newChunkId;
++ yaffs_ExtendedTags newTags;
++
++ yaffs_Device *dev = in->myDev;
++
++ yaffs_CheckGarbageCollection(dev);
++
++ /* Get the previous chunk at this location in the file if it exists */
++ prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
++
++ /* Set up new tags */
++ yaffs_InitialiseTags(&newTags);
++
++ newTags.chunkId = chunkInInode;
++ newTags.objectId = in->objectId;
++ newTags.serialNumber =
++ (prevChunkId > 0) ? prevTags.serialNumber + 1 : 1;
++ newTags.byteCount = nBytes;
++
++ if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
++ YBUG();
++ }
++
++ /*
++ * If there isn't already a chunk there then do a dummy
++ * insert to make sue we have the desired tnode structure.
++ */
++ if(prevChunkId < 1 &&
++ yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0) != YAFFS_OK)
++ return -1;
++
++ newChunkId =
++ yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
++ useReserve);
++
++ if (newChunkId > 0) {
++ yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
++
++ if (prevChunkId > 0)
++ yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
++
++ yaffs_CheckFileSanity(in);
++ }
++ return newChunkId;
++
++}
++
++/* UpdateObjectHeader updates the header on NAND for an object.
++ * If name is not NULL, then that new name is used.
++ */
++int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
++ int isShrink, int shadows)
++{
++
++ yaffs_BlockInfo *bi;
++
++ yaffs_Device *dev = in->myDev;
++
++ int prevChunkId;
++ int retVal = 0;
++ int result = 0;
++
++ int newChunkId;
++ yaffs_ExtendedTags newTags;
++ yaffs_ExtendedTags oldTags;
++ YCHAR *alias = NULL;
++
++ __u8 *buffer = NULL;
++ YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
++
++ yaffs_ObjectHeader *oh = NULL;
++
++ yaffs_strcpy(oldName, _Y("silly old name"));
++
++
++ if (!in->fake ||
++ in == dev->rootDir || /* The rootDir should also be saved */
++ force) {
++
++ yaffs_CheckGarbageCollection(dev);
++ yaffs_CheckObjectDetailsLoaded(in);
++
++ buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
++ oh = (yaffs_ObjectHeader *) buffer;
++
++ prevChunkId = in->hdrChunk;
++
++ if (prevChunkId > 0) {
++ result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
++ buffer, &oldTags);
++
++ yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
++
++ memcpy(oldName, oh->name, sizeof(oh->name));
++ }
++
++ memset(buffer, 0xFF, dev->nDataBytesPerChunk);
++
++ oh->type = in->variantType;
++ oh->yst_mode = in->yst_mode;
++ oh->shadowsObject = oh->inbandShadowsObject = shadows;
++
++#ifdef CONFIG_YAFFS_WINCE
++ oh->win_atime[0] = in->win_atime[0];
++ oh->win_ctime[0] = in->win_ctime[0];
++ oh->win_mtime[0] = in->win_mtime[0];
++ oh->win_atime[1] = in->win_atime[1];
++ oh->win_ctime[1] = in->win_ctime[1];
++ oh->win_mtime[1] = in->win_mtime[1];
++#else
++ oh->yst_uid = in->yst_uid;
++ oh->yst_gid = in->yst_gid;
++ oh->yst_atime = in->yst_atime;
++ oh->yst_mtime = in->yst_mtime;
++ oh->yst_ctime = in->yst_ctime;
++ oh->yst_rdev = in->yst_rdev;
++#endif
++ if (in->parent)
++ oh->parentObjectId = in->parent->objectId;
++ else
++ oh->parentObjectId = 0;
++
++ if (name && *name) {
++ memset(oh->name, 0, sizeof(oh->name));
++ yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
++ } else if (prevChunkId > 0)
++ memcpy(oh->name, oldName, sizeof(oh->name));
++ else
++ memset(oh->name, 0, sizeof(oh->name));
++
++ oh->isShrink = isShrink;
++
++ switch (in->variantType) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Should not happen */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ oh->fileSize =
++ (oh->parentObjectId == YAFFS_OBJECTID_DELETED
++ || oh->parentObjectId ==
++ YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
++ fileVariant.fileSize;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ oh->equivalentObjectId =
++ in->variant.hardLinkVariant.equivalentObjectId;
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ alias = in->variant.symLinkVariant.alias;
++ if(!alias)
++ alias = _Y("no alias");
++ yaffs_strncpy(oh->alias,
++ alias,
++ YAFFS_MAX_ALIAS_LENGTH);
++ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
++ break;
++ }
++
++ /* Tags */
++ yaffs_InitialiseTags(&newTags);
++ in->serial++;
++ newTags.chunkId = 0;
++ newTags.objectId = in->objectId;
++ newTags.serialNumber = in->serial;
++
++ /* Add extra info for file header */
++
++ newTags.extraHeaderInfoAvailable = 1;
++ newTags.extraParentObjectId = oh->parentObjectId;
++ newTags.extraFileLength = oh->fileSize;
++ newTags.extraIsShrinkHeader = oh->isShrink;
++ newTags.extraEquivalentObjectId = oh->equivalentObjectId;
++ newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
++ newTags.extraObjectType = in->variantType;
++
++ yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
++
++ /* Create new chunk in NAND */
++ newChunkId =
++ yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
++ (prevChunkId > 0) ? 1 : 0);
++
++ if (newChunkId >= 0) {
++
++ in->hdrChunk = newChunkId;
++
++ if (prevChunkId > 0) {
++ yaffs_DeleteChunk(dev, prevChunkId, 1,
++ __LINE__);
++ }
++
++ if (!yaffs_ObjectHasCachedWriteData(in))
++ in->dirty = 0;
++
++ /* If this was a shrink, then mark the block that the chunk lives on */
++ if (isShrink) {
++ bi = yaffs_GetBlockInfo(in->myDev,
++ newChunkId / in->myDev->nChunksPerBlock);
++ bi->hasShrinkHeader = 1;
++ }
++
++ }
++
++ retVal = newChunkId;
++
++ }
++
++ if (buffer)
++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
++
++ return retVal;
++}
++
++/*------------------------ Short Operations Cache ----------------------------------------
++ * In many situations where there is no high level buffering (eg WinCE) a lot of
++ * reads might be short sequential reads, and a lot of writes may be short
++ * sequential writes. eg. scanning/writing a jpeg file.
++ * In these cases, a short read/write cache can provide a huge perfomance benefit
++ * with dumb-as-a-rock code.
++ * In Linux, the page cache provides read buffering aand the short op cache provides write
++ * buffering.
++ *
++ * There are a limited number (~10) of cache chunks per device so that we don't
++ * need a very intelligent search.
++ */
++
++static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
++{
++ yaffs_Device *dev = obj->myDev;
++ int i;
++ yaffs_ChunkCache *cache;
++ int nCaches = obj->myDev->nShortOpCaches;
++
++ for (i = 0; i < nCaches; i++) {
++ cache = &dev->srCache[i];
++ if (cache->object == obj &&
++ cache->dirty)
++ return 1;
++ }
++
++ return 0;
++}
++
++
++static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
++{
++ yaffs_Device *dev = obj->myDev;
++ int lowest = -99; /* Stop compiler whining. */
++ int i;
++ yaffs_ChunkCache *cache;
++ int chunkWritten = 0;
++ int nCaches = obj->myDev->nShortOpCaches;
++
++ if (nCaches > 0) {
++ do {
++ cache = NULL;
++
++ /* Find the dirty cache for this object with the lowest chunk id. */
++ for (i = 0; i < nCaches; i++) {
++ if (dev->srCache[i].object == obj &&
++ dev->srCache[i].dirty) {
++ if (!cache
++ || dev->srCache[i].chunkId <
++ lowest) {
++ cache = &dev->srCache[i];
++ lowest = cache->chunkId;
++ }
++ }
++ }
++
++ if (cache && !cache->locked) {
++ /* Write it out and free it up */
++
++ chunkWritten =
++ yaffs_WriteChunkDataToObject(cache->object,
++ cache->chunkId,
++ cache->data,
++ cache->nBytes,
++ 1);
++ cache->dirty = 0;
++ cache->object = NULL;
++ }
++
++ } while (cache && chunkWritten > 0);
++
++ if (cache) {
++ /* Hoosterman, disk full while writing cache out. */
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
++
++ }
++ }
++
++}
++
++/*yaffs_FlushEntireDeviceCache(dev)
++ *
++ *
++ */
++
++void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
++{
++ yaffs_Object *obj;
++ int nCaches = dev->nShortOpCaches;
++ int i;
++
++ /* Find a dirty object in the cache and flush it...
++ * until there are no further dirty objects.
++ */
++ do {
++ obj = NULL;
++ for (i = 0; i < nCaches && !obj; i++) {
++ if (dev->srCache[i].object &&
++ dev->srCache[i].dirty)
++ obj = dev->srCache[i].object;
++
++ }
++ if (obj)
++ yaffs_FlushFilesChunkCache(obj);
++
++ } while (obj);
++
++}
++
++
++/* Grab us a cache chunk for use.
++ * First look for an empty one.
++ * Then look for the least recently used non-dirty one.
++ * Then look for the least recently used dirty one...., flush and look again.
++ */
++static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
++{
++ int i;
++
++ if (dev->nShortOpCaches > 0) {
++ for (i = 0; i < dev->nShortOpCaches; i++) {
++ if (!dev->srCache[i].object)
++ return &dev->srCache[i];
++ }
++ }
++
++ return NULL;
++}
++
++static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
++{
++ yaffs_ChunkCache *cache;
++ yaffs_Object *theObj;
++ int usage;
++ int i;
++ int pushout;
++
++ if (dev->nShortOpCaches > 0) {
++ /* Try find a non-dirty one... */
++
++ cache = yaffs_GrabChunkCacheWorker(dev);
++
++ if (!cache) {
++ /* They were all dirty, find the last recently used object and flush
++ * its cache, then find again.
++ * NB what's here is not very accurate, we actually flush the object
++ * the last recently used page.
++ */
++
++ /* With locking we can't assume we can use entry zero */
++
++ theObj = NULL;
++ usage = -1;
++ cache = NULL;
++ pushout = -1;
++
++ for (i = 0; i < dev->nShortOpCaches; i++) {
++ if (dev->srCache[i].object &&
++ !dev->srCache[i].locked &&
++ (dev->srCache[i].lastUse < usage || !cache)) {
++ usage = dev->srCache[i].lastUse;
++ theObj = dev->srCache[i].object;
++ cache = &dev->srCache[i];
++ pushout = i;
++ }
++ }
++
++ if (!cache || cache->dirty) {
++ /* Flush and try again */
++ yaffs_FlushFilesChunkCache(theObj);
++ cache = yaffs_GrabChunkCacheWorker(dev);
++ }
++
++ }
++ return cache;
++ } else
++ return NULL;
++
++}
++
++/* Find a cached chunk */
++static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
++ int chunkId)
++{
++ yaffs_Device *dev = obj->myDev;
++ int i;
++ if (dev->nShortOpCaches > 0) {
++ for (i = 0; i < dev->nShortOpCaches; i++) {
++ if (dev->srCache[i].object == obj &&
++ dev->srCache[i].chunkId == chunkId) {
++ dev->cacheHits++;
++
++ return &dev->srCache[i];
++ }
++ }
++ }
++ return NULL;
++}
++
++/* Mark the chunk for the least recently used algorithym */
++static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
++ int isAWrite)
++{
++
++ if (dev->nShortOpCaches > 0) {
++ if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
++ /* Reset the cache usages */
++ int i;
++ for (i = 1; i < dev->nShortOpCaches; i++)
++ dev->srCache[i].lastUse = 0;
++
++ dev->srLastUse = 0;
++ }
++
++ dev->srLastUse++;
++
++ cache->lastUse = dev->srLastUse;
++
++ if (isAWrite)
++ cache->dirty = 1;
++ }
++}
++
++/* Invalidate a single cache page.
++ * Do this when a whole page gets written,
++ * ie the short cache for this page is no longer valid.
++ */
++static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
++{
++ if (object->myDev->nShortOpCaches > 0) {
++ yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
++
++ if (cache)
++ cache->object = NULL;
++ }
++}
++
++/* Invalidate all the cache pages associated with this object
++ * Do this whenever ther file is deleted or resized.
++ */
++static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
++{
++ int i;
++ yaffs_Device *dev = in->myDev;
++
++ if (dev->nShortOpCaches > 0) {
++ /* Invalidate it. */
++ for (i = 0; i < dev->nShortOpCaches; i++) {
++ if (dev->srCache[i].object == in)
++ dev->srCache[i].object = NULL;
++ }
++ }
++}
++
++/*--------------------- Checkpointing --------------------*/
++
++
++static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
++{
++ yaffs_CheckpointValidity cp;
++
++ memset(&cp, 0, sizeof(cp));
++
++ cp.structType = sizeof(cp);
++ cp.magic = YAFFS_MAGIC;
++ cp.version = YAFFS_CHECKPOINT_VERSION;
++ cp.head = (head) ? 1 : 0;
++
++ return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
++ 1 : 0;
++}
++
++static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
++{
++ yaffs_CheckpointValidity cp;
++ int ok;
++
++ ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ if (ok)
++ ok = (cp.structType == sizeof(cp)) &&
++ (cp.magic == YAFFS_MAGIC) &&
++ (cp.version == YAFFS_CHECKPOINT_VERSION) &&
++ (cp.head == ((head) ? 1 : 0));
++ return ok ? 1 : 0;
++}
++
++static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
++ yaffs_Device *dev)
++{
++ cp->nErasedBlocks = dev->nErasedBlocks;
++ cp->allocationBlock = dev->allocationBlock;
++ cp->allocationPage = dev->allocationPage;
++ cp->nFreeChunks = dev->nFreeChunks;
++
++ cp->nDeletedFiles = dev->nDeletedFiles;
++ cp->nUnlinkedFiles = dev->nUnlinkedFiles;
++ cp->nBackgroundDeletions = dev->nBackgroundDeletions;
++ cp->sequenceNumber = dev->sequenceNumber;
++ cp->oldestDirtySequence = dev->oldestDirtySequence;
++
++}
++
++static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
++ yaffs_CheckpointDevice *cp)
++{
++ dev->nErasedBlocks = cp->nErasedBlocks;
++ dev->allocationBlock = cp->allocationBlock;
++ dev->allocationPage = cp->allocationPage;
++ dev->nFreeChunks = cp->nFreeChunks;
++
++ dev->nDeletedFiles = cp->nDeletedFiles;
++ dev->nUnlinkedFiles = cp->nUnlinkedFiles;
++ dev->nBackgroundDeletions = cp->nBackgroundDeletions;
++ dev->sequenceNumber = cp->sequenceNumber;
++ dev->oldestDirtySequence = cp->oldestDirtySequence;
++}
++
++
++static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
++{
++ yaffs_CheckpointDevice cp;
++ __u32 nBytes;
++ __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
++
++ int ok;
++
++ /* Write device runtime values*/
++ yaffs_DeviceToCheckpointDevice(&cp, dev);
++ cp.structType = sizeof(cp);
++
++ ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ /* Write block info */
++ if (ok) {
++ nBytes = nBlocks * sizeof(yaffs_BlockInfo);
++ ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
++ }
++
++ /* Write chunk bits */
++ if (ok) {
++ nBytes = nBlocks * dev->chunkBitmapStride;
++ ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
++ }
++ return ok ? 1 : 0;
++
++}
++
++static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
++{
++ yaffs_CheckpointDevice cp;
++ __u32 nBytes;
++ __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
++
++ int ok;
++
++ ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (!ok)
++ return 0;
++
++ if (cp.structType != sizeof(cp))
++ return 0;
++
++
++ yaffs_CheckpointDeviceToDevice(dev, &cp);
++
++ nBytes = nBlocks * sizeof(yaffs_BlockInfo);
++
++ ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
++
++ if (!ok)
++ return 0;
++ nBytes = nBlocks * dev->chunkBitmapStride;
++
++ ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
++
++ return ok ? 1 : 0;
++}
++
++static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
++ yaffs_Object *obj)
++{
++
++ cp->objectId = obj->objectId;
++ cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
++ cp->hdrChunk = obj->hdrChunk;
++ cp->variantType = obj->variantType;
++ cp->deleted = obj->deleted;
++ cp->softDeleted = obj->softDeleted;
++ cp->unlinked = obj->unlinked;
++ cp->fake = obj->fake;
++ cp->renameAllowed = obj->renameAllowed;
++ cp->unlinkAllowed = obj->unlinkAllowed;
++ cp->serial = obj->serial;
++ cp->nDataChunks = obj->nDataChunks;
++
++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
++ cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
++ else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
++ cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
++}
++
++static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
++{
++
++ yaffs_Object *parent;
++
++ if (obj->variantType != cp->variantType) {
++ T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
++ TCONT("chunk %d does not match existing object type %d")
++ TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
++ obj->variantType));
++ return 0;
++ }
++
++ obj->objectId = cp->objectId;
++
++ if (cp->parentId)
++ parent = yaffs_FindOrCreateObjectByNumber(
++ obj->myDev,
++ cp->parentId,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ else
++ parent = NULL;
++
++ if (parent) {
++ if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
++ TCONT(" chunk %d Parent type, %d, not directory")
++ TENDSTR),
++ cp->objectId, cp->parentId, cp->variantType,
++ cp->hdrChunk, parent->variantType));
++ return 0;
++ }
++ yaffs_AddObjectToDirectory(parent, obj);
++ }
++
++ obj->hdrChunk = cp->hdrChunk;
++ obj->variantType = cp->variantType;
++ obj->deleted = cp->deleted;
++ obj->softDeleted = cp->softDeleted;
++ obj->unlinked = cp->unlinked;
++ obj->fake = cp->fake;
++ obj->renameAllowed = cp->renameAllowed;
++ obj->unlinkAllowed = cp->unlinkAllowed;
++ obj->serial = cp->serial;
++ obj->nDataChunks = cp->nDataChunks;
++
++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
++ obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
++ else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
++ obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
++
++ if (obj->hdrChunk > 0)
++ obj->lazyLoaded = 1;
++ return 1;
++}
++
++
++
++static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
++ __u32 level, int chunkOffset)
++{
++ int i;
++ yaffs_Device *dev = in->myDev;
++ int ok = 1;
++ int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
++
++ if (tnodeSize < sizeof(yaffs_Tnode))
++ tnodeSize = sizeof(yaffs_Tnode);
++
++
++ if (tn) {
++ if (level > 0) {
++
++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
++ if (tn->internal[i]) {
++ ok = yaffs_CheckpointTnodeWorker(in,
++ tn->internal[i],
++ level - 1,
++ (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
++ }
++ }
++ } else if (level == 0) {
++ __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
++ ok = (yaffs_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
++ if (ok)
++ ok = (yaffs_CheckpointWrite(dev, tn, tnodeSize) == tnodeSize);
++ }
++ }
++
++ return ok;
++
++}
++
++static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
++{
++ __u32 endMarker = ~0;
++ int ok = 1;
++
++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
++ ok = yaffs_CheckpointTnodeWorker(obj,
++ obj->variant.fileVariant.top,
++ obj->variant.fileVariant.topLevel,
++ 0);
++ if (ok)
++ ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
++ sizeof(endMarker));
++ }
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
++{
++ __u32 baseChunk;
++ int ok = 1;
++ yaffs_Device *dev = obj->myDev;
++ yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
++ yaffs_Tnode *tn;
++ int nread = 0;
++ int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
++
++ if (tnodeSize < sizeof(yaffs_Tnode))
++ tnodeSize = sizeof(yaffs_Tnode);
++
++ ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
++
++ while (ok && (~baseChunk)) {
++ nread++;
++ /* Read level 0 tnode */
++
++
++ tn = yaffs_GetTnodeRaw(dev);
++ if (tn)
++ ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize);
++ else
++ ok = 0;
++
++ if (tn && ok)
++ ok = yaffs_AddOrFindLevel0Tnode(dev,
++ fileStructPtr,
++ baseChunk,
++ tn) ? 1 : 0;
++
++ if (ok)
++ ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
++
++ }
++
++ T(YAFFS_TRACE_CHECKPOINT, (
++ TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
++ nread, baseChunk, ok));
++
++ return ok ? 1 : 0;
++}
++
++
++static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
++{
++ yaffs_Object *obj;
++ yaffs_CheckpointObject cp;
++ int i;
++ int ok = 1;
++ struct ylist_head *lh;
++
++
++ /* Iterate through the objects in each hash entry,
++ * dumping them to the checkpointing stream.
++ */
++
++ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
++ ylist_for_each(lh, &dev->objectBucket[i].list) {
++ if (lh) {
++ obj = ylist_entry(lh, yaffs_Object, hashLink);
++ if (!obj->deferedFree) {
++ yaffs_ObjectToCheckpointObject(&cp, obj);
++ cp.structType = sizeof(cp);
++
++ T(YAFFS_TRACE_CHECKPOINT, (
++ TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
++ cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, obj));
++
++ ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
++ ok = yaffs_WriteCheckpointTnodes(obj);
++ }
++ }
++ }
++ }
++
++ /* Dump end of list */
++ memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
++ cp.structType = sizeof(cp);
++
++ if (ok)
++ ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
++{
++ yaffs_Object *obj;
++ yaffs_CheckpointObject cp;
++ int ok = 1;
++ int done = 0;
++ yaffs_Object *hardList = NULL;
++
++ while (ok && !done) {
++ ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
++ if (cp.structType != sizeof(cp)) {
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
++ cp.structType, (int)sizeof(cp), ok));
++ ok = 0;
++ }
++
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
++ cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
++
++ if (ok && cp.objectId == ~0)
++ done = 1;
++ else if (ok) {
++ obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
++ if (obj) {
++ ok = yaffs_CheckpointObjectToObject(obj, &cp);
++ if (!ok)
++ break;
++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
++ ok = yaffs_ReadCheckpointTnodes(obj);
++ } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
++ obj->hardLinks.next =
++ (struct ylist_head *) hardList;
++ hardList = obj;
++ }
++ } else
++ ok = 0;
++ }
++ }
++
++ if (ok)
++ yaffs_HardlinkFixup(dev, hardList);
++
++ return ok ? 1 : 0;
++}
++
++static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
++{
++ __u32 checkpointSum;
++ int ok;
++
++ yaffs_GetCheckpointSum(dev, &checkpointSum);
++
++ ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
++
++ if (!ok)
++ return 0;
++
++ return 1;
++}
++
++static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
++{
++ __u32 checkpointSum0;
++ __u32 checkpointSum1;
++ int ok;
++
++ yaffs_GetCheckpointSum(dev, &checkpointSum0);
++
++ ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
++
++ if (!ok)
++ return 0;
++
++ if (checkpointSum0 != checkpointSum1)
++ return 0;
++
++ return 1;
++}
++
++
++static int yaffs_WriteCheckpointData(yaffs_Device *dev)
++{
++ int ok = 1;
++
++ if (dev->skipCheckpointWrite || !dev->isYaffs2) {
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
++ ok = 0;
++ }
++
++ if (ok)
++ ok = yaffs_CheckpointOpen(dev, 1);
++
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
++ ok = yaffs_WriteCheckpointValidityMarker(dev, 1);
++ }
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
++ ok = yaffs_WriteCheckpointDevice(dev);
++ }
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
++ ok = yaffs_WriteCheckpointObjects(dev);
++ }
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
++ ok = yaffs_WriteCheckpointValidityMarker(dev, 0);
++ }
++
++ if (ok)
++ ok = yaffs_WriteCheckpointSum(dev);
++
++ if (!yaffs_CheckpointClose(dev))
++ ok = 0;
++
++ if (ok)
++ dev->isCheckpointed = 1;
++ else
++ dev->isCheckpointed = 0;
++
++ return dev->isCheckpointed;
++}
++
++static int yaffs_ReadCheckpointData(yaffs_Device *dev)
++{
++ int ok = 1;
++
++ if (dev->skipCheckpointRead || !dev->isYaffs2) {
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
++ ok = 0;
++ }
++
++ if (ok)
++ ok = yaffs_CheckpointOpen(dev, 0); /* open for read */
++
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
++ ok = yaffs_ReadCheckpointValidityMarker(dev, 1);
++ }
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
++ ok = yaffs_ReadCheckpointDevice(dev);
++ }
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
++ ok = yaffs_ReadCheckpointObjects(dev);
++ }
++ if (ok) {
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
++ ok = yaffs_ReadCheckpointValidityMarker(dev, 0);
++ }
++
++ if (ok) {
++ ok = yaffs_ReadCheckpointSum(dev);
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
++ }
++
++ if (!yaffs_CheckpointClose(dev))
++ ok = 0;
++
++ if (ok)
++ dev->isCheckpointed = 1;
++ else
++ dev->isCheckpointed = 0;
++
++ return ok ? 1 : 0;
++
++}
++
++static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
++{
++ if (dev->isCheckpointed ||
++ dev->blocksInCheckpoint > 0) {
++ dev->isCheckpointed = 0;
++ yaffs_CheckpointInvalidateStream(dev);
++ if (dev->superBlock && dev->markSuperBlockDirty)
++ dev->markSuperBlockDirty(dev->superBlock);
++ }
++}
++
++
++int yaffs_CheckpointSave(yaffs_Device *dev)
++{
++
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
++
++ yaffs_VerifyObjects(dev);
++ yaffs_VerifyBlocks(dev);
++ yaffs_VerifyFreeChunks(dev);
++
++ if (!dev->isCheckpointed) {
++ yaffs_InvalidateCheckpoint(dev);
++ yaffs_WriteCheckpointData(dev);
++ }
++
++ T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
++
++ return dev->isCheckpointed;
++}
++
++int yaffs_CheckpointRestore(yaffs_Device *dev)
++{
++ int retval;
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
++
++ retval = yaffs_ReadCheckpointData(dev);
++
++ if (dev->isCheckpointed) {
++ yaffs_VerifyObjects(dev);
++ yaffs_VerifyBlocks(dev);
++ yaffs_VerifyFreeChunks(dev);
++ }
++
++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
++
++ return retval;
++}
++
++/*--------------------- File read/write ------------------------
++ * Read and write have very similar structures.
++ * In general the read/write has three parts to it
++ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
++ * Some complete chunks
++ * An incomplete chunk to end off with
++ *
++ * Curve-balls: the first chunk might also be the last chunk.
++ */
++
++int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
++ int nBytes)
++{
++
++ int chunk;
++ __u32 start;
++ int nToCopy;
++ int n = nBytes;
++ int nDone = 0;
++ yaffs_ChunkCache *cache;
++
++ yaffs_Device *dev;
++
++ dev = in->myDev;
++
++ while (n > 0) {
++ /* chunk = offset / dev->nDataBytesPerChunk + 1; */
++ /* start = offset % dev->nDataBytesPerChunk; */
++ yaffs_AddrToChunk(dev, offset, &chunk, &start);
++ chunk++;
++
++ /* OK now check for the curveball where the start and end are in
++ * the same chunk.
++ */
++ if ((start + n) < dev->nDataBytesPerChunk)
++ nToCopy = n;
++ else
++ nToCopy = dev->nDataBytesPerChunk - start;
++
++ cache = yaffs_FindChunkCache(in, chunk);
++
++ /* If the chunk is already in the cache or it is less than a whole chunk
++ * or we're using inband tags then use the cache (if there is caching)
++ * else bypass the cache.
++ */
++ if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
++ if (dev->nShortOpCaches > 0) {
++
++ /* If we can't find the data in the cache, then load it up. */
++
++ if (!cache) {
++ cache = yaffs_GrabChunkCache(in->myDev);
++ cache->object = in;
++ cache->chunkId = chunk;
++ cache->dirty = 0;
++ cache->locked = 0;
++ yaffs_ReadChunkDataFromObject(in, chunk,
++ cache->
++ data);
++ cache->nBytes = 0;
++ }
++
++ yaffs_UseChunkCache(dev, cache, 0);
++
++ cache->locked = 1;
++
++
++ memcpy(buffer, &cache->data[start], nToCopy);
++
++ cache->locked = 0;
++ } else {
++ /* Read into the local buffer then copy..*/
++
++ __u8 *localBuffer =
++ yaffs_GetTempBuffer(dev, __LINE__);
++ yaffs_ReadChunkDataFromObject(in, chunk,
++ localBuffer);
++
++ memcpy(buffer, &localBuffer[start], nToCopy);
++
++
++ yaffs_ReleaseTempBuffer(dev, localBuffer,
++ __LINE__);
++ }
++
++ } else {
++
++ /* A full chunk. Read directly into the supplied buffer. */
++ yaffs_ReadChunkDataFromObject(in, chunk, buffer);
++
++ }
++
++ n -= nToCopy;
++ offset += nToCopy;
++ buffer += nToCopy;
++ nDone += nToCopy;
++
++ }
++
++ return nDone;
++}
++
++int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
++ int nBytes, int writeThrough)
++{
++
++ int chunk;
++ __u32 start;
++ int nToCopy;
++ int n = nBytes;
++ int nDone = 0;
++ int nToWriteBack;
++ int startOfWrite = offset;
++ int chunkWritten = 0;
++ __u32 nBytesRead;
++ __u32 chunkStart;
++
++ yaffs_Device *dev;
++
++ dev = in->myDev;
++
++ while (n > 0 && chunkWritten >= 0) {
++ /* chunk = offset / dev->nDataBytesPerChunk + 1; */
++ /* start = offset % dev->nDataBytesPerChunk; */
++ yaffs_AddrToChunk(dev, offset, &chunk, &start);
++
++ if (chunk * dev->nDataBytesPerChunk + start != offset ||
++ start >= dev->nDataBytesPerChunk) {
++ T(YAFFS_TRACE_ERROR, (
++ TSTR("AddrToChunk of offset %d gives chunk %d start %d"
++ TENDSTR),
++ (int)offset, chunk, start));
++ }
++ chunk++;
++
++ /* OK now check for the curveball where the start and end are in
++ * the same chunk.
++ */
++
++ if ((start + n) < dev->nDataBytesPerChunk) {
++ nToCopy = n;
++
++ /* Now folks, to calculate how many bytes to write back....
++ * If we're overwriting and not writing to then end of file then
++ * we need to write back as much as was there before.
++ */
++
++ chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
++
++ if (chunkStart > in->variant.fileVariant.fileSize)
++ nBytesRead = 0; /* Past end of file */
++ else
++ nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
++
++ if (nBytesRead > dev->nDataBytesPerChunk)
++ nBytesRead = dev->nDataBytesPerChunk;
++
++ nToWriteBack =
++ (nBytesRead >
++ (start + n)) ? nBytesRead : (start + n);
++
++ if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
++ YBUG();
++
++ } else {
++ nToCopy = dev->nDataBytesPerChunk - start;
++ nToWriteBack = dev->nDataBytesPerChunk;
++ }
++
++ if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
++ /* An incomplete start or end chunk (or maybe both start and end chunk),
++ * or we're using inband tags, so we want to use the cache buffers.
++ */
++ if (dev->nShortOpCaches > 0) {
++ yaffs_ChunkCache *cache;
++ /* If we can't find the data in the cache, then load the cache */
++ cache = yaffs_FindChunkCache(in, chunk);
++
++ if (!cache
++ && yaffs_CheckSpaceForAllocation(in->
++ myDev)) {
++ cache = yaffs_GrabChunkCache(in->myDev);
++ cache->object = in;
++ cache->chunkId = chunk;
++ cache->dirty = 0;
++ cache->locked = 0;
++ yaffs_ReadChunkDataFromObject(in, chunk,
++ cache->
++ data);
++ } else if (cache &&
++ !cache->dirty &&
++ !yaffs_CheckSpaceForAllocation(in->myDev)) {
++ /* Drop the cache if it was a read cache item and
++ * no space check has been made for it.
++ */
++ cache = NULL;
++ }
++
++ if (cache) {
++ yaffs_UseChunkCache(dev, cache, 1);
++ cache->locked = 1;
++
++
++ memcpy(&cache->data[start], buffer,
++ nToCopy);
++
++
++ cache->locked = 0;
++ cache->nBytes = nToWriteBack;
++
++ if (writeThrough) {
++ chunkWritten =
++ yaffs_WriteChunkDataToObject
++ (cache->object,
++ cache->chunkId,
++ cache->data, cache->nBytes,
++ 1);
++ cache->dirty = 0;
++ }
++
++ } else {
++ chunkWritten = -1; /* fail the write */
++ }
++ } else {
++ /* An incomplete start or end chunk (or maybe both start and end chunk)
++ * Read into the local buffer then copy, then copy over and write back.
++ */
++
++ __u8 *localBuffer =
++ yaffs_GetTempBuffer(dev, __LINE__);
++
++ yaffs_ReadChunkDataFromObject(in, chunk,
++ localBuffer);
++
++
++
++ memcpy(&localBuffer[start], buffer, nToCopy);
++
++ chunkWritten =
++ yaffs_WriteChunkDataToObject(in, chunk,
++ localBuffer,
++ nToWriteBack,
++ 0);
++
++ yaffs_ReleaseTempBuffer(dev, localBuffer,
++ __LINE__);
++
++ }
++
++ } else {
++ /* A full chunk. Write directly from the supplied buffer. */
++
++
++
++ chunkWritten =
++ yaffs_WriteChunkDataToObject(in, chunk, buffer,
++ dev->nDataBytesPerChunk,
++ 0);
++
++ /* Since we've overwritten the cached data, we better invalidate it. */
++ yaffs_InvalidateChunkCache(in, chunk);
++ }
++
++ if (chunkWritten >= 0) {
++ n -= nToCopy;
++ offset += nToCopy;
++ buffer += nToCopy;
++ nDone += nToCopy;
++ }
++
++ }
++
++ /* Update file object */
++
++ if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
++ in->variant.fileVariant.fileSize = (startOfWrite + nDone);
++
++ in->dirty = 1;
++
++ return nDone;
++}
++
++
++/* ---------------------- File resizing stuff ------------------ */
++
++static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
++{
++
++ yaffs_Device *dev = in->myDev;
++ int oldFileSize = in->variant.fileVariant.fileSize;
++
++ int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
++
++ int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
++ dev->nDataBytesPerChunk;
++ int i;
++ int chunkId;
++
++ /* Delete backwards so that we don't end up with holes if
++ * power is lost part-way through the operation.
++ */
++ for (i = lastDel; i >= startDel; i--) {
++ /* NB this could be optimised somewhat,
++ * eg. could retrieve the tags and write them without
++ * using yaffs_DeleteChunk
++ */
++
++ chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
++ if (chunkId > 0) {
++ if (chunkId <
++ (dev->internalStartBlock * dev->nChunksPerBlock)
++ || chunkId >=
++ ((dev->internalEndBlock +
++ 1) * dev->nChunksPerBlock)) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("Found daft chunkId %d for %d" TENDSTR),
++ chunkId, i));
++ } else {
++ in->nDataChunks--;
++ yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
++ }
++ }
++ }
++
++}
++
++int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
++{
++
++ int oldFileSize = in->variant.fileVariant.fileSize;
++ __u32 newSizeOfPartialChunk;
++ int newFullChunks;
++
++ yaffs_Device *dev = in->myDev;
++
++ yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
++
++ yaffs_FlushFilesChunkCache(in);
++ yaffs_InvalidateWholeChunkCache(in);
++
++ yaffs_CheckGarbageCollection(dev);
++
++ if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
++ return YAFFS_FAIL;
++
++ if (newSize == oldFileSize)
++ return YAFFS_OK;
++
++ if (newSize < oldFileSize) {
++
++ yaffs_PruneResizedChunks(in, newSize);
++
++ if (newSizeOfPartialChunk != 0) {
++ int lastChunk = 1 + newFullChunks;
++
++ __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
++
++ /* Got to read and rewrite the last chunk with its new size and zero pad */
++ yaffs_ReadChunkDataFromObject(in, lastChunk,
++ localBuffer);
++
++ memset(localBuffer + newSizeOfPartialChunk, 0,
++ dev->nDataBytesPerChunk - newSizeOfPartialChunk);
++
++ yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
++ newSizeOfPartialChunk, 1);
++
++ yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
++ }
++
++ in->variant.fileVariant.fileSize = newSize;
++
++ yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
++ } else {
++ /* newsSize > oldFileSize */
++ in->variant.fileVariant.fileSize = newSize;
++ }
++
++
++ /* Write a new object header to reflect the resize.
++ * show we've shrunk the file, if need be
++ * Do this only if the file is not in the deleted directories
++ * and is not shadowed.
++ */
++ if (in->parent &&
++ !in->isShadowed &&
++ in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
++ in->parent->objectId != YAFFS_OBJECTID_DELETED)
++ yaffs_UpdateObjectHeader(in, NULL, 0,
++ (newSize < oldFileSize) ? 1 : 0, 0);
++
++ return YAFFS_OK;
++}
++
++loff_t yaffs_GetFileSize(yaffs_Object *obj)
++{
++ YCHAR *alias = NULL;
++ obj = yaffs_GetEquivalentObject(obj);
++
++ switch (obj->variantType) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return obj->variant.fileVariant.fileSize;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ alias = obj->variant.symLinkVariant.alias;
++ if(!alias)
++ return 0;
++ return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH);
++ default:
++ return 0;
++ }
++}
++
++
++
++int yaffs_FlushFile(yaffs_Object *in, int updateTime, int dataSync)
++{
++ int retVal;
++ if (in->dirty) {
++ yaffs_FlushFilesChunkCache(in);
++ if(dataSync) /* Only sync data */
++ retVal=YAFFS_OK;
++ else {
++ if (updateTime) {
++#ifdef CONFIG_YAFFS_WINCE
++ yfsd_WinFileTimeNow(in->win_mtime);
++#else
++
++ in->yst_mtime = Y_CURRENT_TIME;
++
++#endif
++ }
++
++ retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
++ 0) ? YAFFS_OK : YAFFS_FAIL;
++ }
++ } else {
++ retVal = YAFFS_OK;
++ }
++
++ return retVal;
++
++}
++
++static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
++{
++
++ /* First off, invalidate the file's data in the cache, without flushing. */
++ yaffs_InvalidateWholeChunkCache(in);
++
++ if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
++ /* Move to the unlinked directory so we have a record that it was deleted. */
++ yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
++
++ }
++
++ yaffs_RemoveObjectFromDirectory(in);
++ yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
++ in->hdrChunk = 0;
++
++ yaffs_FreeObject(in);
++ return YAFFS_OK;
++
++}
++
++/* yaffs_DeleteFile deletes the whole file data
++ * and the inode associated with the file.
++ * It does not delete the links associated with the file.
++ */
++static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
++{
++
++ int retVal;
++ int immediateDeletion = 0;
++
++ if (!in->myInode)
++ immediateDeletion = 1;
++
++ if (immediateDeletion) {
++ retVal =
++ yaffs_ChangeObjectName(in, in->myDev->deletedDir,
++ _Y("deleted"), 0, 0);
++ T(YAFFS_TRACE_TRACING,
++ (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
++ in->objectId));
++ in->deleted = 1;
++ in->myDev->nDeletedFiles++;
++ if (1 || in->myDev->isYaffs2)
++ yaffs_ResizeFile(in, 0);
++ yaffs_SoftDeleteFile(in);
++ } else {
++ retVal =
++ yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
++ _Y("unlinked"), 0, 0);
++ }
++
++
++ return retVal;
++}
++
++int yaffs_DeleteFile(yaffs_Object *in)
++{
++ int retVal = YAFFS_OK;
++ int deleted = in->deleted;
++
++ yaffs_ResizeFile(in, 0);
++
++ if (in->nDataChunks > 0) {
++ /* Use soft deletion if there is data in the file.
++ * That won't be the case if it has been resized to zero.
++ */
++ if (!in->unlinked)
++ retVal = yaffs_UnlinkFileIfNeeded(in);
++
++ if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
++ in->deleted = 1;
++ deleted = 1;
++ in->myDev->nDeletedFiles++;
++ yaffs_SoftDeleteFile(in);
++ }
++ return deleted ? YAFFS_OK : YAFFS_FAIL;
++ } else {
++ /* The file has no data chunks so we toss it immediately */
++ yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
++ in->variant.fileVariant.top = NULL;
++ yaffs_DoGenericObjectDeletion(in);
++
++ return YAFFS_OK;
++ }
++}
++
++static int yaffs_IsNonEmptyDirectory(yaffs_Object *obj)
++{
++ return (obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) &&
++ !(ylist_empty(&obj->variant.directoryVariant.children));
++}
++
++static int yaffs_DeleteDirectory(yaffs_Object *obj)
++{
++ /* First check that the directory is empty. */
++ if (yaffs_IsNonEmptyDirectory(obj))
++ return YAFFS_FAIL;
++
++ return yaffs_DoGenericObjectDeletion(obj);
++}
++
++static int yaffs_DeleteSymLink(yaffs_Object *in)
++{
++ if(in->variant.symLinkVariant.alias)
++ YFREE(in->variant.symLinkVariant.alias);
++ in->variant.symLinkVariant.alias=NULL;
++
++ return yaffs_DoGenericObjectDeletion(in);
++}
++
++static int yaffs_DeleteHardLink(yaffs_Object *in)
++{
++ /* remove this hardlink from the list assocaited with the equivalent
++ * object
++ */
++ ylist_del_init(&in->hardLinks);
++ return yaffs_DoGenericObjectDeletion(in);
++}
++
++int yaffs_DeleteObject(yaffs_Object *obj)
++{
++int retVal = -1;
++ switch (obj->variantType) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ retVal = yaffs_DeleteFile(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ return yaffs_DeleteDirectory(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ retVal = yaffs_DeleteSymLink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ retVal = yaffs_DeleteHardLink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ retVal = yaffs_DoGenericObjectDeletion(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ retVal = 0;
++ break; /* should not happen. */
++ }
++
++ return retVal;
++}
++
++static int yaffs_UnlinkWorker(yaffs_Object *obj)
++{
++
++ int immediateDeletion = 0;
++
++ if (!obj->myInode)
++ immediateDeletion = 1;
++
++ if(obj)
++ yaffs_UpdateParent(obj->parent);
++
++ if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
++ return yaffs_DeleteHardLink(obj);
++ } else if (!ylist_empty(&obj->hardLinks)) {
++ /* Curve ball: We're unlinking an object that has a hardlink.
++ *
++ * This problem arises because we are not strictly following
++ * The Linux link/inode model.
++ *
++ * We can't really delete the object.
++ * Instead, we do the following:
++ * - Select a hardlink.
++ * - Unhook it from the hard links
++ * - Move it from its parent directory (so that the rename can work)
++ * - Rename the object to the hardlink's name.
++ * - Delete the hardlink
++ */
++
++ yaffs_Object *hl;
++ yaffs_Object *parent;
++ int retVal;
++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
++
++ yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
++ parent = hl->parent;
++
++ ylist_del_init(&hl->hardLinks);
++
++ yaffs_AddObjectToDirectory(obj->myDev->unlinkedDir, hl);
++
++ retVal = yaffs_ChangeObjectName(obj,parent, name, 0, 0);
++
++ if (retVal == YAFFS_OK)
++ retVal = yaffs_DoGenericObjectDeletion(hl);
++
++ return retVal;
++
++ } else if (immediateDeletion) {
++ switch (obj->variantType) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return yaffs_DeleteFile(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ return yaffs_DeleteDirectory(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ return yaffs_DeleteSymLink(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ return yaffs_DoGenericObjectDeletion(obj);
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ default:
++ return YAFFS_FAIL;
++ }
++ } else if(yaffs_IsNonEmptyDirectory(obj))
++ return YAFFS_FAIL;
++ else
++ return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
++ _Y("unlinked"), 0, 0);
++}
++
++
++static int yaffs_UnlinkObject(yaffs_Object *obj)
++{
++
++ if (obj && obj->unlinkAllowed)
++ return yaffs_UnlinkWorker(obj);
++
++ return YAFFS_FAIL;
++
++}
++int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
++{
++ yaffs_Object *obj;
++
++ obj = yaffs_FindObjectByName(dir, name);
++ return yaffs_UnlinkObject(obj);
++}
++
++/*----------------------- Initialisation Scanning ---------------------- */
++
++static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
++ int backwardScanning)
++{
++ yaffs_Object *obj;
++
++ if (!backwardScanning) {
++ /* Handle YAFFS1 forward scanning case
++ * For YAFFS1 we always do the deletion
++ */
++
++ } else {
++ /* Handle YAFFS2 case (backward scanning)
++ * If the shadowed object exists then ignore.
++ */
++ obj = yaffs_FindObjectByNumber(dev, objId);
++ if(obj)
++ return;
++ }
++
++ /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
++ * We put it in unlinked dir to be cleaned up after the scanning
++ */
++ obj =
++ yaffs_FindOrCreateObjectByNumber(dev, objId,
++ YAFFS_OBJECT_TYPE_FILE);
++ if (!obj)
++ return;
++ obj->isShadowed = 1;
++ yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
++ obj->variant.fileVariant.shrinkSize = 0;
++ obj->valid = 1; /* So that we don't read any other info for this file */
++
++}
++
++typedef struct {
++ int seq;
++ int block;
++} yaffs_BlockIndex;
++
++
++static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
++{
++ yaffs_Object *hl;
++ yaffs_Object *in;
++
++ while (hardList) {
++ hl = hardList;
++ hardList = (yaffs_Object *) (hardList->hardLinks.next);
++
++ in = yaffs_FindObjectByNumber(dev,
++ hl->variant.hardLinkVariant.
++ equivalentObjectId);
++
++ if (in) {
++ /* Add the hardlink pointers */
++ hl->variant.hardLinkVariant.equivalentObject = in;
++ ylist_add(&hl->hardLinks, &in->hardLinks);
++ } else {
++ /* Todo Need to report/handle this better.
++ * Got a problem... hardlink to a non-existant object
++ */
++ hl->variant.hardLinkVariant.equivalentObject = NULL;
++ YINIT_LIST_HEAD(&hl->hardLinks);
++
++ }
++ }
++}
++
++
++
++
++
++static int ybicmp(const void *a, const void *b)
++{
++ register int aseq = ((yaffs_BlockIndex *)a)->seq;
++ register int bseq = ((yaffs_BlockIndex *)b)->seq;
++ register int ablock = ((yaffs_BlockIndex *)a)->block;
++ register int bblock = ((yaffs_BlockIndex *)b)->block;
++ if (aseq == bseq)
++ return ablock - bblock;
++ else
++ return aseq - bseq;
++}
++
++
++struct yaffs_ShadowFixerStruct {
++ int objectId;
++ int shadowedId;
++ struct yaffs_ShadowFixerStruct *next;
++};
++
++
++static void yaffs_StripDeletedObjects(yaffs_Device *dev)
++{
++ /*
++ * Sort out state of unlinked and deleted objects after scanning.
++ */
++ struct ylist_head *i;
++ struct ylist_head *n;
++ yaffs_Object *l;
++
++ /* Soft delete all the unlinked files */
++ ylist_for_each_safe(i, n,
++ &dev->unlinkedDir->variant.directoryVariant.children) {
++ if (i) {
++ l = ylist_entry(i, yaffs_Object, siblings);
++ yaffs_DeleteObject(l);
++ }
++ }
++
++ ylist_for_each_safe(i, n,
++ &dev->deletedDir->variant.directoryVariant.children) {
++ if (i) {
++ l = ylist_entry(i, yaffs_Object, siblings);
++ yaffs_DeleteObject(l);
++ }
++ }
++
++}
++
++/*
++ * This code iterates through all the objects making sure that they are rooted.
++ * Any unrooted objects are re-rooted in lost+found.
++ * An object needs to be in one of:
++ * - Directly under deleted, unlinked
++ * - Directly or indirectly under root.
++ *
++ * Note:
++ * This code assumes that we don't ever change the current relationships between
++ * directories:
++ * rootDir->parent == unlinkedDir->parent == deletedDir->parent == NULL
++ * lostNfound->parent == rootDir
++ *
++ * This fixes the problem where directories might have inadvertently been deleted
++ * leaving the object "hanging" without being rooted in the directory tree.
++ */
++
++static int yaffs_HasNULLParent(yaffs_Device *dev, yaffs_Object *obj)
++{
++ return (obj == dev->deletedDir ||
++ obj == dev->unlinkedDir||
++ obj == dev->rootDir);
++}
++
++static void yaffs_FixHangingObjects(yaffs_Device *dev)
++{
++ yaffs_Object *obj;
++ yaffs_Object *parent;
++ int i;
++ struct ylist_head *lh;
++ struct ylist_head *n;
++ int depthLimit;
++ int hanging;
++
++
++ /* Iterate through the objects in each hash entry,
++ * looking at each object.
++ * Make sure it is rooted.
++ */
++
++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
++ ylist_for_each_safe(lh, n, &dev->objectBucket[i].list) {
++ if (lh) {
++ obj = ylist_entry(lh, yaffs_Object, hashLink);
++ parent= obj->parent;
++
++ if(yaffs_HasNULLParent(dev,obj)){
++ /* These directories are not hanging */
++ hanging = 0;
++ }
++ else if(!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
++ hanging = 1;
++ else if(yaffs_HasNULLParent(dev,parent))
++ hanging = 0;
++ else {
++ /*
++ * Need to follow the parent chain to see if it is hanging.
++ */
++ hanging = 0;
++ depthLimit=100;
++
++ while(parent != dev->rootDir &&
++ parent->parent &&
++ parent->parent->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
++ depthLimit > 0){
++ parent = parent->parent;
++ depthLimit--;
++ }
++ if(parent != dev->rootDir)
++ hanging = 1;
++ }
++ if(hanging){
++ T(YAFFS_TRACE_SCAN,
++ (TSTR("Hanging object %d moved to lost and found" TENDSTR),obj->objectId));
++ yaffs_AddObjectToDirectory(dev->lostNFoundDir,obj);
++ }
++ }
++ }
++ }
++}
++
++
++/*
++ * Delete directory contents for cleaning up lost and found.
++ */
++static void yaffs_DeleteDirectoryContents(yaffs_Object *dir)
++{
++ yaffs_Object *obj;
++ struct ylist_head *lh;
++ struct ylist_head *n;
++
++ if(dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
++ YBUG();
++
++ ylist_for_each_safe(lh, n, &dir->variant.directoryVariant.children) {
++ if (lh) {
++ obj = ylist_entry(lh, yaffs_Object, siblings);
++ if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
++ yaffs_DeleteDirectoryContents(obj);
++
++ T(YAFFS_TRACE_SCAN,
++ (TSTR("Deleting lost_found object %d" TENDSTR),
++ obj->objectId));
++
++ /* Need to use UnlinkObject since Delete would not handle
++ * hardlinked objects correctly.
++ */
++ yaffs_UnlinkObject(obj);
++ }
++ }
++}
++
++static void yaffs_EmptyLostAndFound(yaffs_Device *dev)
++{
++ yaffs_DeleteDirectoryContents(dev->lostNFoundDir);
++}
++
++static int yaffs_Scan(yaffs_Device *dev)
++{
++ yaffs_ExtendedTags tags;
++ int blk;
++ int blockIterator;
++ int startIterator;
++ int endIterator;
++ int result;
++
++ int chunk;
++ int c;
++ int deleted;
++ yaffs_BlockState state;
++ yaffs_Object *hardList = NULL;
++ yaffs_BlockInfo *bi;
++ __u32 sequenceNumber;
++ yaffs_ObjectHeader *oh;
++ yaffs_Object *in;
++ yaffs_Object *parent;
++
++ int alloc_failed = 0;
++
++ struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
++
++
++ __u8 *chunkData;
++
++
++
++ T(YAFFS_TRACE_SCAN,
++ (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),
++ dev->internalStartBlock, dev->internalEndBlock));
++
++ chunkData = yaffs_GetTempBuffer(dev, __LINE__);
++
++ dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++ /* Scan all the blocks to determine their state */
++ for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
++ bi = yaffs_GetBlockInfo(dev, blk);
++ yaffs_ClearChunkBits(dev, blk);
++ bi->pagesInUse = 0;
++ bi->softDeletions = 0;
++
++ yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
++
++ bi->blockState = state;
++ bi->sequenceNumber = sequenceNumber;
++
++ if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
++ bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
++
++ T(YAFFS_TRACE_SCAN_DEBUG,
++ (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
++ state, sequenceNumber));
++
++ if (state == YAFFS_BLOCK_STATE_DEAD) {
++ T(YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("block %d is bad" TENDSTR), blk));
++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
++ T(YAFFS_TRACE_SCAN_DEBUG,
++ (TSTR("Block empty " TENDSTR)));
++ dev->nErasedBlocks++;
++ dev->nFreeChunks += dev->nChunksPerBlock;
++ }
++ }
++
++ startIterator = dev->internalStartBlock;
++ endIterator = dev->internalEndBlock;
++
++ /* For each block.... */
++ for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
++ blockIterator++) {
++
++ YYIELD();
++
++ YYIELD();
++
++ blk = blockIterator;
++
++ bi = yaffs_GetBlockInfo(dev, blk);
++ state = bi->blockState;
++
++ deleted = 0;
++
++ /* For each chunk in each block that needs scanning....*/
++ for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&
++ state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
++ /* Read the tags and decide what to do */
++ chunk = blk * dev->nChunksPerBlock + c;
++
++ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
++ &tags);
++
++ /* Let's have a good look at this chunk... */
++
++ if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
++ /* YAFFS1 only...
++ * A deleted chunk
++ */
++ deleted++;
++ dev->nFreeChunks++;
++ /*T((" %d %d deleted\n",blk,c)); */
++ } else if (!tags.chunkUsed) {
++ /* An unassigned chunk in the block
++ * This means that either the block is empty or
++ * this is the one being allocated from
++ */
++
++ if (c == 0) {
++ /* We're looking at the first chunk in the block so the block is unused */
++ state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->nErasedBlocks++;
++ } else {
++ /* this is the block being allocated from */
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ (" Allocating from %d %d" TENDSTR),
++ blk, c));
++ state = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->allocationBlock = blk;
++ dev->allocationPage = c;
++ dev->allocationBlockFinder = blk;
++ /* Set block finder here to encourage the allocator to go forth from here. */
++
++ }
++
++ dev->nFreeChunks += (dev->nChunksPerBlock - c);
++ } else if (tags.chunkId > 0) {
++ /* chunkId > 0 so it is a data chunk... */
++ unsigned int endpos;
++
++ yaffs_SetChunkBit(dev, blk, c);
++ bi->pagesInUse++;
++
++ in = yaffs_FindOrCreateObjectByNumber(dev,
++ tags.
++ objectId,
++ YAFFS_OBJECT_TYPE_FILE);
++ /* PutChunkIntoFile checks for a clash (two data chunks with
++ * the same chunkId).
++ */
++
++ if (!in)
++ alloc_failed = 1;
++
++ if (in) {
++ if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
++ alloc_failed = 1;
++ }
++
++ endpos =
++ (tags.chunkId - 1) * dev->nDataBytesPerChunk +
++ tags.byteCount;
++ if (in &&
++ in->variantType == YAFFS_OBJECT_TYPE_FILE
++ && in->variant.fileVariant.scannedFileSize <
++ endpos) {
++ in->variant.fileVariant.
++ scannedFileSize = endpos;
++ if (!dev->useHeaderFileSize) {
++ in->variant.fileVariant.
++ fileSize =
++ in->variant.fileVariant.
++ scannedFileSize;
++ }
++
++ }
++ /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
++ } else {
++ /* chunkId == 0, so it is an ObjectHeader.
++ * Thus, we read in the object header and make the object
++ */
++ yaffs_SetChunkBit(dev, blk, c);
++ bi->pagesInUse++;
++
++ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
++ chunkData,
++ NULL);
++
++ oh = (yaffs_ObjectHeader *) chunkData;
++
++ in = yaffs_FindObjectByNumber(dev,
++ tags.objectId);
++ if (in && in->variantType != oh->type) {
++ /* This should not happen, but somehow
++ * Wev'e ended up with an objectId that has been reused but not yet
++ * deleted, and worse still it has changed type. Delete the old object.
++ */
++
++ yaffs_DeleteObject(in);
++
++ in = 0;
++ }
++
++ in = yaffs_FindOrCreateObjectByNumber(dev,
++ tags.
++ objectId,
++ oh->type);
++
++ if (!in)
++ alloc_failed = 1;
++
++ if (in && oh->shadowsObject > 0) {
++
++ struct yaffs_ShadowFixerStruct *fixer;
++ fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
++ if (fixer) {
++ fixer->next = shadowFixerList;
++ shadowFixerList = fixer;
++ fixer->objectId = tags.objectId;
++ fixer->shadowedId = oh->shadowsObject;
++ }
++
++ }
++
++ if (in && in->valid) {
++ /* We have already filled this one. We have a duplicate and need to resolve it. */
++
++ unsigned existingSerial = in->serial;
++ unsigned newSerial = tags.serialNumber;
++
++ if (((existingSerial + 1) & 3) == newSerial) {
++ /* Use new one - destroy the exisiting one */
++ yaffs_DeleteChunk(dev,
++ in->hdrChunk,
++ 1, __LINE__);
++ in->valid = 0;
++ } else {
++ /* Use existing - destroy this one. */
++ yaffs_DeleteChunk(dev, chunk, 1,
++ __LINE__);
++ }
++ }
++
++ if (in && !in->valid &&
++ (tags.objectId == YAFFS_OBJECTID_ROOT ||
++ tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
++ /* We only load some info, don't fiddle with directory structure */
++ in->valid = 1;
++ in->variantType = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++#ifdef CONFIG_YAFFS_WINCE
++ in->win_atime[0] = oh->win_atime[0];
++ in->win_ctime[0] = oh->win_ctime[0];
++ in->win_mtime[0] = oh->win_mtime[0];
++ in->win_atime[1] = oh->win_atime[1];
++ in->win_ctime[1] = oh->win_ctime[1];
++ in->win_mtime[1] = oh->win_mtime[1];
++#else
++ in->yst_uid = oh->yst_uid;
++ in->yst_gid = oh->yst_gid;
++ in->yst_atime = oh->yst_atime;
++ in->yst_mtime = oh->yst_mtime;
++ in->yst_ctime = oh->yst_ctime;
++ in->yst_rdev = oh->yst_rdev;
++#endif
++ in->hdrChunk = chunk;
++ in->serial = tags.serialNumber;
++
++ } else if (in && !in->valid) {
++ /* we need to load this info */
++
++ in->valid = 1;
++ in->variantType = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++#ifdef CONFIG_YAFFS_WINCE
++ in->win_atime[0] = oh->win_atime[0];
++ in->win_ctime[0] = oh->win_ctime[0];
++ in->win_mtime[0] = oh->win_mtime[0];
++ in->win_atime[1] = oh->win_atime[1];
++ in->win_ctime[1] = oh->win_ctime[1];
++ in->win_mtime[1] = oh->win_mtime[1];
++#else
++ in->yst_uid = oh->yst_uid;
++ in->yst_gid = oh->yst_gid;
++ in->yst_atime = oh->yst_atime;
++ in->yst_mtime = oh->yst_mtime;
++ in->yst_ctime = oh->yst_ctime;
++ in->yst_rdev = oh->yst_rdev;
++#endif
++ in->hdrChunk = chunk;
++ in->serial = tags.serialNumber;
++
++ yaffs_SetObjectName(in, oh->name);
++ in->dirty = 0;
++
++ /* directory stuff...
++ * hook up to parent
++ */
++
++ parent =
++ yaffs_FindOrCreateObjectByNumber
++ (dev, oh->parentObjectId,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ if (!parent)
++ alloc_failed = 1;
++ if (parent && parent->variantType ==
++ YAFFS_OBJECT_TYPE_UNKNOWN) {
++ /* Set up as a directory */
++ parent->variantType =
++ YAFFS_OBJECT_TYPE_DIRECTORY;
++ YINIT_LIST_HEAD(&parent->variant.
++ directoryVariant.
++ children);
++ } else if (!parent || parent->variantType !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ /* Hoosterman, another problem....
++ * We're trying to use a non-directory as a directory
++ */
++
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++ TENDSTR)));
++ parent = dev->lostNFoundDir;
++ }
++
++ yaffs_AddObjectToDirectory(parent, in);
++
++ if (0 && (parent == dev->deletedDir ||
++ parent == dev->unlinkedDir)) {
++ in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
++ dev->nDeletedFiles++;
++ }
++ /* Note re hardlinks.
++ * Since we might scan a hardlink before its equivalent object is scanned
++ * we put them all in a list.
++ * After scanning is complete, we should have all the objects, so we run through this
++ * list and fix up all the chains.
++ */
++
++ switch (in->variantType) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Todo got a problem */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++ if (dev->useHeaderFileSize)
++
++ in->variant.fileVariant.
++ fileSize =
++ oh->fileSize;
++
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ in->variant.hardLinkVariant.
++ equivalentObjectId =
++ oh->equivalentObjectId;
++ in->hardLinks.next =
++ (struct ylist_head *)
++ hardList;
++ hardList = in;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ in->variant.symLinkVariant.alias =
++ yaffs_CloneString(oh->alias);
++ if (!in->variant.symLinkVariant.alias)
++ alloc_failed = 1;
++ break;
++ }
++
++ }
++ }
++ }
++
++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
++ /* If we got this far while scanning, then the block is fully allocated.*/
++ state = YAFFS_BLOCK_STATE_FULL;
++ }
++
++ if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ /* If the block was partially allocated then treat it as fully allocated.*/
++ state = YAFFS_BLOCK_STATE_FULL;
++ dev->allocationBlock = -1;
++ }
++
++ bi->blockState = state;
++
++ /* Now let's see if it was dirty */
++ if (bi->pagesInUse == 0 &&
++ !bi->hasShrinkHeader &&
++ bi->blockState == YAFFS_BLOCK_STATE_FULL) {
++ yaffs_BlockBecameDirty(dev, blk);
++ }
++
++ }
++
++
++ /* Ok, we've done all the scanning.
++ * Fix up the hard link chains.
++ * We should now have scanned all the objects, now it's time to add these
++ * hardlinks.
++ */
++
++ yaffs_HardlinkFixup(dev, hardList);
++
++ /* Fix up any shadowed objects */
++ {
++ struct yaffs_ShadowFixerStruct *fixer;
++ yaffs_Object *obj;
++
++ while (shadowFixerList) {
++ fixer = shadowFixerList;
++ shadowFixerList = fixer->next;
++ /* Complete the rename transaction by deleting the shadowed object
++ * then setting the object header to unshadowed.
++ */
++ obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
++ if (obj)
++ yaffs_DeleteObject(obj);
++
++ obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
++
++ if (obj)
++ yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
++
++ YFREE(fixer);
++ }
++ }
++
++ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
++
++ if (alloc_failed)
++ return YAFFS_FAIL;
++
++ T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
++
++
++ return YAFFS_OK;
++}
++
++static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
++{
++ __u8 *chunkData;
++ yaffs_ObjectHeader *oh;
++ yaffs_Device *dev;
++ yaffs_ExtendedTags tags;
++ int result;
++ int alloc_failed = 0;
++
++ if (!in)
++ return;
++
++ dev = in->myDev;
++
++#if 0
++ T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
++ in->objectId,
++ in->lazyLoaded ? "not yet" : "already"));
++#endif
++
++ if (in->lazyLoaded && in->hdrChunk > 0) {
++ in->lazyLoaded = 0;
++ chunkData = yaffs_GetTempBuffer(dev, __LINE__);
++
++ result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
++ oh = (yaffs_ObjectHeader *) chunkData;
++
++ in->yst_mode = oh->yst_mode;
++#ifdef CONFIG_YAFFS_WINCE
++ in->win_atime[0] = oh->win_atime[0];
++ in->win_ctime[0] = oh->win_ctime[0];
++ in->win_mtime[0] = oh->win_mtime[0];
++ in->win_atime[1] = oh->win_atime[1];
++ in->win_ctime[1] = oh->win_ctime[1];
++ in->win_mtime[1] = oh->win_mtime[1];
++#else
++ in->yst_uid = oh->yst_uid;
++ in->yst_gid = oh->yst_gid;
++ in->yst_atime = oh->yst_atime;
++ in->yst_mtime = oh->yst_mtime;
++ in->yst_ctime = oh->yst_ctime;
++ in->yst_rdev = oh->yst_rdev;
++
++#endif
++ yaffs_SetObjectName(in, oh->name);
++
++ if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
++ in->variant.symLinkVariant.alias =
++ yaffs_CloneString(oh->alias);
++ if (!in->variant.symLinkVariant.alias)
++ alloc_failed = 1; /* Not returned to caller */
++ }
++
++ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
++ }
++}
++
++static int yaffs_ScanBackwards(yaffs_Device *dev)
++{
++ yaffs_ExtendedTags tags;
++ int blk;
++ int blockIterator;
++ int startIterator;
++ int endIterator;
++ int nBlocksToScan = 0;
++
++ int chunk;
++ int result;
++ int c;
++ int deleted;
++ yaffs_BlockState state;
++ yaffs_Object *hardList = NULL;
++ yaffs_BlockInfo *bi;
++ __u32 sequenceNumber;
++ yaffs_ObjectHeader *oh;
++ yaffs_Object *in;
++ yaffs_Object *parent;
++ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
++ int itsUnlinked;
++ __u8 *chunkData;
++
++ int fileSize;
++ int isShrink;
++ int foundChunksInBlock;
++ int equivalentObjectId;
++ int alloc_failed = 0;
++
++
++ yaffs_BlockIndex *blockIndex = NULL;
++ int altBlockIndex = 0;
++
++ if (!dev->isYaffs2) {
++ T(YAFFS_TRACE_SCAN,
++ (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..."
++ TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
++
++
++ dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
++
++ blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
++
++ if (!blockIndex) {
++ blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
++ altBlockIndex = 1;
++ }
++
++ if (!blockIndex) {
++ T(YAFFS_TRACE_SCAN,
++ (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ dev->blocksInCheckpoint = 0;
++
++ chunkData = yaffs_GetTempBuffer(dev, __LINE__);
++
++ /* Scan all the blocks to determine their state */
++ for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
++ bi = yaffs_GetBlockInfo(dev, blk);
++ yaffs_ClearChunkBits(dev, blk);
++ bi->pagesInUse = 0;
++ bi->softDeletions = 0;
++
++ yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
++
++ bi->blockState = state;
++ bi->sequenceNumber = sequenceNumber;
++
++ if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
++ bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
++ if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
++ bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
++
++ T(YAFFS_TRACE_SCAN_DEBUG,
++ (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
++ state, sequenceNumber));
++
++
++ if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++ dev->blocksInCheckpoint++;
++
++ } else if (state == YAFFS_BLOCK_STATE_DEAD) {
++ T(YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("block %d is bad" TENDSTR), blk));
++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
++ T(YAFFS_TRACE_SCAN_DEBUG,
++ (TSTR("Block empty " TENDSTR)));
++ dev->nErasedBlocks++;
++ dev->nFreeChunks += dev->nChunksPerBlock;
++ } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
++
++ /* Determine the highest sequence number */
++ if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
++ sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
++
++ blockIndex[nBlocksToScan].seq = sequenceNumber;
++ blockIndex[nBlocksToScan].block = blk;
++
++ nBlocksToScan++;
++
++ if (sequenceNumber >= dev->sequenceNumber)
++ dev->sequenceNumber = sequenceNumber;
++ } else {
++ /* TODO: Nasty sequence number! */
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ ("Block scanning block %d has bad sequence number %d"
++ TENDSTR), blk, sequenceNumber));
++
++ }
++ }
++ }
++
++ T(YAFFS_TRACE_SCAN,
++ (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
++
++
++
++ YYIELD();
++
++ /* Sort the blocks */
++#ifndef CONFIG_YAFFS_USE_OWN_SORT
++ {
++ /* Use qsort now. */
++ yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);
++ }
++#else
++ {
++ /* Dungy old bubble sort... */
++
++ yaffs_BlockIndex temp;
++ int i;
++ int j;
++
++ for (i = 0; i < nBlocksToScan; i++)
++ for (j = i + 1; j < nBlocksToScan; j++)
++ if (blockIndex[i].seq > blockIndex[j].seq) {
++ temp = blockIndex[j];
++ blockIndex[j] = blockIndex[i];
++ blockIndex[i] = temp;
++ }
++ }
++#endif
++
++ YYIELD();
++
++ T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
++
++ /* Now scan the blocks looking at the data. */
++ startIterator = 0;
++ endIterator = nBlocksToScan - 1;
++ T(YAFFS_TRACE_SCAN_DEBUG,
++ (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
++
++ /* For each block.... backwards */
++ for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
++ blockIterator--) {
++ /* Cooperative multitasking! This loop can run for so
++ long that watchdog timers expire. */
++ YYIELD();
++
++ /* get the block to scan in the correct order */
++ blk = blockIndex[blockIterator].block;
++
++ bi = yaffs_GetBlockInfo(dev, blk);
++
++
++ state = bi->blockState;
++
++ deleted = 0;
++
++ /* For each chunk in each block that needs scanning.... */
++ foundChunksInBlock = 0;
++ for (c = dev->nChunksPerBlock - 1;
++ !alloc_failed && c >= 0 &&
++ (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
++ state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
++ /* Scan backwards...
++ * Read the tags and decide what to do
++ */
++
++ chunk = blk * dev->nChunksPerBlock + c;
++
++ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
++ &tags);
++
++ /* Let's have a good look at this chunk... */
++
++ if (!tags.chunkUsed) {
++ /* An unassigned chunk in the block.
++ * If there are used chunks after this one, then
++ * it is a chunk that was skipped due to failing the erased
++ * check. Just skip it so that it can be deleted.
++ * But, more typically, We get here when this is an unallocated
++ * chunk and his means that either the block is empty or
++ * this is the one being allocated from
++ */
++
++ if (foundChunksInBlock) {
++ /* This is a chunk that was skipped due to failing the erased check */
++ } else if (c == 0) {
++ /* We're looking at the first chunk in the block so the block is unused */
++ state = YAFFS_BLOCK_STATE_EMPTY;
++ dev->nErasedBlocks++;
++ } else {
++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
++ state == YAFFS_BLOCK_STATE_ALLOCATING) {
++ if (dev->sequenceNumber == bi->sequenceNumber) {
++ /* this is the block being allocated from */
++
++ T(YAFFS_TRACE_SCAN,
++ (TSTR
++ (" Allocating from %d %d"
++ TENDSTR), blk, c));
++
++ state = YAFFS_BLOCK_STATE_ALLOCATING;
++ dev->allocationBlock = blk;
++ dev->allocationPage = c;
++ dev->allocationBlockFinder = blk;
++ } else {
++ /* This is a partially written block that is not
++ * the current allocation block.
++ */
++
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("Partially written block %d detected" TENDSTR),
++ blk));
++ }
++ }
++ }
++
++ dev->nFreeChunks++;
++
++ } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
++ T(YAFFS_TRACE_SCAN,
++ (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
++ blk, c));
++
++ dev->nFreeChunks++;
++
++ } else if (tags.chunkId > 0) {
++ /* chunkId > 0 so it is a data chunk... */
++ unsigned int endpos;
++ __u32 chunkBase =
++ (tags.chunkId - 1) * dev->nDataBytesPerChunk;
++
++ foundChunksInBlock = 1;
++
++
++ yaffs_SetChunkBit(dev, blk, c);
++ bi->pagesInUse++;
++
++ in = yaffs_FindOrCreateObjectByNumber(dev,
++ tags.
++ objectId,
++ YAFFS_OBJECT_TYPE_FILE);
++ if (!in) {
++ /* Out of memory */
++ alloc_failed = 1;
++ }
++
++ if (in &&
++ in->variantType == YAFFS_OBJECT_TYPE_FILE
++ && chunkBase <
++ in->variant.fileVariant.shrinkSize) {
++ /* This has not been invalidated by a resize */
++ if (!yaffs_PutChunkIntoFile(in, tags.chunkId,
++ chunk, -1)) {
++ alloc_failed = 1;
++ }
++
++ /* File size is calculated by looking at the data chunks if we have not
++ * seen an object header yet. Stop this practice once we find an object header.
++ */
++ endpos =
++ (tags.chunkId -
++ 1) * dev->nDataBytesPerChunk +
++ tags.byteCount;
++
++ if (!in->valid && /* have not got an object header yet */
++ in->variant.fileVariant.
++ scannedFileSize < endpos) {
++ in->variant.fileVariant.
++ scannedFileSize = endpos;
++ in->variant.fileVariant.
++ fileSize =
++ in->variant.fileVariant.
++ scannedFileSize;
++ }
++
++ } else if (in) {
++ /* This chunk has been invalidated by a resize, so delete */
++ yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
++
++ }
++ } else {
++ /* chunkId == 0, so it is an ObjectHeader.
++ * Thus, we read in the object header and make the object
++ */
++ foundChunksInBlock = 1;
++
++ yaffs_SetChunkBit(dev, blk, c);
++ bi->pagesInUse++;
++
++ oh = NULL;
++ in = NULL;
++
++ if (tags.extraHeaderInfoAvailable) {
++ in = yaffs_FindOrCreateObjectByNumber
++ (dev, tags.objectId,
++ tags.extraObjectType);
++ if (!in)
++ alloc_failed = 1;
++ }
++
++ if (!in ||
++ (!in->valid && dev->disableLazyLoad) ||
++ tags.extraShadows ||
++ (!in->valid &&
++ (tags.objectId == YAFFS_OBJECTID_ROOT ||
++ tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
++
++ /* If we don't have valid info then we need to read the chunk
++ * TODO In future we can probably defer reading the chunk and
++ * living with invalid data until needed.
++ */
++
++ result = yaffs_ReadChunkWithTagsFromNAND(dev,
++ chunk,
++ chunkData,
++ NULL);
++
++ oh = (yaffs_ObjectHeader *) chunkData;
++
++ if (dev->inbandTags) {
++ /* Fix up the header if they got corrupted by inband tags */
++ oh->shadowsObject = oh->inbandShadowsObject;
++ oh->isShrink = oh->inbandIsShrink;
++ }
++
++ if (!in) {
++ in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
++ if (!in)
++ alloc_failed = 1;
++ }
++
++ }
++
++ if (!in) {
++ /* TODO Hoosterman we have a problem! */
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
++ TENDSTR), tags.objectId, chunk));
++ continue;
++ }
++
++ if (in->valid) {
++ /* We have already filled this one.
++ * We have a duplicate that will be discarded, but
++ * we first have to suck out resize info if it is a file.
++ */
++
++ if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
++ ((oh &&
++ oh->type == YAFFS_OBJECT_TYPE_FILE) ||
++ (tags.extraHeaderInfoAvailable &&
++ tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
++ __u32 thisSize =
++ (oh) ? oh->fileSize : tags.
++ extraFileLength;
++ __u32 parentObjectId =
++ (oh) ? oh->
++ parentObjectId : tags.
++ extraParentObjectId;
++
++
++ isShrink =
++ (oh) ? oh->isShrink : tags.
++ extraIsShrinkHeader;
++
++ /* If it is deleted (unlinked at start also means deleted)
++ * we treat the file size as being zeroed at this point.
++ */
++ if (parentObjectId ==
++ YAFFS_OBJECTID_DELETED
++ || parentObjectId ==
++ YAFFS_OBJECTID_UNLINKED) {
++ thisSize = 0;
++ isShrink = 1;
++ }
++
++ if (isShrink &&
++ in->variant.fileVariant.
++ shrinkSize > thisSize) {
++ in->variant.fileVariant.
++ shrinkSize =
++ thisSize;
++ }
++
++ if (isShrink)
++ bi->hasShrinkHeader = 1;
++
++ }
++ /* Use existing - destroy this one. */
++ yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
++
++ }
++
++ if (!in->valid && in->variantType !=
++ (oh ? oh->type : tags.extraObjectType))
++ T(YAFFS_TRACE_ERROR, (
++ TSTR("yaffs tragedy: Bad object type, "
++ TCONT("%d != %d, for object %d at chunk ")
++ TCONT("%d during scan")
++ TENDSTR), oh ?
++ oh->type : tags.extraObjectType,
++ in->variantType, tags.objectId,
++ chunk));
++
++ if (!in->valid &&
++ (tags.objectId == YAFFS_OBJECTID_ROOT ||
++ tags.objectId ==
++ YAFFS_OBJECTID_LOSTNFOUND)) {
++ /* We only load some info, don't fiddle with directory structure */
++ in->valid = 1;
++
++ if (oh) {
++ in->variantType = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++#ifdef CONFIG_YAFFS_WINCE
++ in->win_atime[0] = oh->win_atime[0];
++ in->win_ctime[0] = oh->win_ctime[0];
++ in->win_mtime[0] = oh->win_mtime[0];
++ in->win_atime[1] = oh->win_atime[1];
++ in->win_ctime[1] = oh->win_ctime[1];
++ in->win_mtime[1] = oh->win_mtime[1];
++#else
++ in->yst_uid = oh->yst_uid;
++ in->yst_gid = oh->yst_gid;
++ in->yst_atime = oh->yst_atime;
++ in->yst_mtime = oh->yst_mtime;
++ in->yst_ctime = oh->yst_ctime;
++ in->yst_rdev = oh->yst_rdev;
++
++#endif
++ } else {
++ in->variantType = tags.extraObjectType;
++ in->lazyLoaded = 1;
++ }
++
++ in->hdrChunk = chunk;
++
++ } else if (!in->valid) {
++ /* we need to load this info */
++
++ in->valid = 1;
++ in->hdrChunk = chunk;
++
++ if (oh) {
++ in->variantType = oh->type;
++
++ in->yst_mode = oh->yst_mode;
++#ifdef CONFIG_YAFFS_WINCE
++ in->win_atime[0] = oh->win_atime[0];
++ in->win_ctime[0] = oh->win_ctime[0];
++ in->win_mtime[0] = oh->win_mtime[0];
++ in->win_atime[1] = oh->win_atime[1];
++ in->win_ctime[1] = oh->win_ctime[1];
++ in->win_mtime[1] = oh->win_mtime[1];
++#else
++ in->yst_uid = oh->yst_uid;
++ in->yst_gid = oh->yst_gid;
++ in->yst_atime = oh->yst_atime;
++ in->yst_mtime = oh->yst_mtime;
++ in->yst_ctime = oh->yst_ctime;
++ in->yst_rdev = oh->yst_rdev;
++#endif
++
++ if (oh->shadowsObject > 0)
++ yaffs_HandleShadowedObject(dev,
++ oh->
++ shadowsObject,
++ 1);
++
++
++
++ yaffs_SetObjectName(in, oh->name);
++ parent =
++ yaffs_FindOrCreateObjectByNumber
++ (dev, oh->parentObjectId,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++
++ fileSize = oh->fileSize;
++ isShrink = oh->isShrink;
++ equivalentObjectId = oh->equivalentObjectId;
++
++ } else {
++ in->variantType = tags.extraObjectType;
++ parent =
++ yaffs_FindOrCreateObjectByNumber
++ (dev, tags.extraParentObjectId,
++ YAFFS_OBJECT_TYPE_DIRECTORY);
++ fileSize = tags.extraFileLength;
++ isShrink = tags.extraIsShrinkHeader;
++ equivalentObjectId = tags.extraEquivalentObjectId;
++ in->lazyLoaded = 1;
++
++ }
++ in->dirty = 0;
++
++ if (!parent)
++ alloc_failed = 1;
++
++ /* directory stuff...
++ * hook up to parent
++ */
++
++ if (parent && parent->variantType ==
++ YAFFS_OBJECT_TYPE_UNKNOWN) {
++ /* Set up as a directory */
++ parent->variantType =
++ YAFFS_OBJECT_TYPE_DIRECTORY;
++ YINIT_LIST_HEAD(&parent->variant.
++ directoryVariant.
++ children);
++ } else if (!parent || parent->variantType !=
++ YAFFS_OBJECT_TYPE_DIRECTORY) {
++ /* Hoosterman, another problem....
++ * We're trying to use a non-directory as a directory
++ */
++
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
++ TENDSTR)));
++ parent = dev->lostNFoundDir;
++ }
++
++ yaffs_AddObjectToDirectory(parent, in);
++
++ itsUnlinked = (parent == dev->deletedDir) ||
++ (parent == dev->unlinkedDir);
++
++ if (isShrink) {
++ /* Mark the block as having a shrinkHeader */
++ bi->hasShrinkHeader = 1;
++ }
++
++ /* Note re hardlinks.
++ * Since we might scan a hardlink before its equivalent object is scanned
++ * we put them all in a list.
++ * After scanning is complete, we should have all the objects, so we run
++ * through this list and fix up all the chains.
++ */
++
++ switch (in->variantType) {
++ case YAFFS_OBJECT_TYPE_UNKNOWN:
++ /* Todo got a problem */
++ break;
++ case YAFFS_OBJECT_TYPE_FILE:
++
++ if (in->variant.fileVariant.
++ scannedFileSize < fileSize) {
++ /* This covers the case where the file size is greater
++ * than where the data is
++ * This will happen if the file is resized to be larger
++ * than its current data extents.
++ */
++ in->variant.fileVariant.fileSize = fileSize;
++ in->variant.fileVariant.scannedFileSize =
++ in->variant.fileVariant.fileSize;
++ }
++
++ if (isShrink &&
++ in->variant.fileVariant.shrinkSize > fileSize) {
++ in->variant.fileVariant.shrinkSize = fileSize;
++ }
++
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ if (!itsUnlinked) {
++ in->variant.hardLinkVariant.equivalentObjectId =
++ equivalentObjectId;
++ in->hardLinks.next =
++ (struct ylist_head *) hardList;
++ hardList = in;
++ }
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ /* Do nothing */
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ if (oh) {
++ in->variant.symLinkVariant.alias =
++ yaffs_CloneString(oh->alias);
++ if (!in->variant.symLinkVariant.alias)
++ alloc_failed = 1;
++ }
++ break;
++ }
++
++ }
++
++ }
++
++ } /* End of scanning for each chunk */
++
++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
++ /* If we got this far while scanning, then the block is fully allocated. */
++ state = YAFFS_BLOCK_STATE_FULL;
++ }
++
++
++ bi->blockState = state;
++
++ /* Now let's see if it was dirty */
++ if (bi->pagesInUse == 0 &&
++ !bi->hasShrinkHeader &&
++ bi->blockState == YAFFS_BLOCK_STATE_FULL) {
++ yaffs_BlockBecameDirty(dev, blk);
++ }
++
++ }
++
++ yaffs_SkipRestOfBlock(dev);
++
++ if (altBlockIndex)
++ YFREE_ALT(blockIndex);
++ else
++ YFREE(blockIndex);
++
++ /* Ok, we've done all the scanning.
++ * Fix up the hard link chains.
++ * We should now have scanned all the objects, now it's time to add these
++ * hardlinks.
++ */
++ yaffs_HardlinkFixup(dev, hardList);
++
++
++ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
++
++ if (alloc_failed)
++ return YAFFS_FAIL;
++
++ T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
++
++ return YAFFS_OK;
++}
++
++/*------------------------------ Directory Functions ----------------------------- */
++
++static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
++{
++ struct ylist_head *lh;
++ yaffs_Object *listObj;
++
++ int count = 0;
++
++ if (!obj) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
++ YBUG();
++ return;
++ }
++
++ if (yaffs_SkipVerification(obj->myDev))
++ return;
++
++ if (!obj->parent) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
++ YBUG();
++ return;
++ }
++
++ if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
++ YBUG();
++ }
++
++ /* Iterate through the objects in each hash entry */
++
++ ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
++ if (lh) {
++ listObj = ylist_entry(lh, yaffs_Object, siblings);
++ yaffs_VerifyObject(listObj);
++ if (obj == listObj)
++ count++;
++ }
++ }
++
++ if (count != 1) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
++ YBUG();
++ }
++}
++
++static void yaffs_VerifyDirectory(yaffs_Object *directory)
++{
++ struct ylist_head *lh;
++ yaffs_Object *listObj;
++
++ if (!directory) {
++ YBUG();
++ return;
++ }
++
++ if (yaffs_SkipFullVerification(directory->myDev))
++ return;
++
++ if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
++ YBUG();
++ }
++
++ /* Iterate through the objects in each hash entry */
++
++ ylist_for_each(lh, &directory->variant.directoryVariant.children) {
++ if (lh) {
++ listObj = ylist_entry(lh, yaffs_Object, siblings);
++ if (listObj->parent != directory) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
++ YBUG();
++ }
++ yaffs_VerifyObjectInDirectory(listObj);
++ }
++ }
++}
++
++/*
++ *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new
++ * link (ie. name) is created or deleted in the directory.
++ *
++ * ie.
++ * create dir/a : update dir's mtime/ctime
++ * rm dir/a: update dir's mtime/ctime
++ * modify dir/a: don't update dir's mtimme/ctime
++ */
++
++static void yaffs_UpdateParent(yaffs_Object *obj)
++{
++ if(!obj)
++ return;
++
++ obj->dirty = 1;
++ obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
++
++ yaffs_UpdateObjectHeader(obj,NULL,0,0,0);
++}
++
++static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
++{
++ yaffs_Device *dev = obj->myDev;
++ yaffs_Object *parent;
++
++ yaffs_VerifyObjectInDirectory(obj);
++ parent = obj->parent;
++
++ yaffs_VerifyDirectory(parent);
++
++ if (dev && dev->removeObjectCallback)
++ dev->removeObjectCallback(obj);
++
++
++ ylist_del_init(&obj->siblings);
++ obj->parent = NULL;
++
++ yaffs_VerifyDirectory(parent);
++}
++
++static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
++ yaffs_Object *obj)
++{
++ if (!directory) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("tragedy: Trying to add an object to a null pointer directory"
++ TENDSTR)));
++ YBUG();
++ return;
++ }
++ if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("tragedy: Trying to add an object to a non-directory"
++ TENDSTR)));
++ YBUG();
++ }
++
++ if (obj->siblings.prev == NULL) {
++ /* Not initialised */
++ YBUG();
++ }
++
++
++ yaffs_VerifyDirectory(directory);
++
++ yaffs_RemoveObjectFromDirectory(obj);
++
++
++ /* Now add it */
++ ylist_add(&obj->siblings, &directory->variant.directoryVariant.children);
++ obj->parent = directory;
++
++ if (directory == obj->myDev->unlinkedDir
++ || directory == obj->myDev->deletedDir) {
++ obj->unlinked = 1;
++ obj->myDev->nUnlinkedFiles++;
++ obj->renameAllowed = 0;
++ }
++
++ yaffs_VerifyDirectory(directory);
++ yaffs_VerifyObjectInDirectory(obj);
++}
++
++yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,
++ const YCHAR *name)
++{
++ int sum;
++
++ struct ylist_head *i;
++ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
++
++ yaffs_Object *l;
++
++ if (!name)
++ return NULL;
++
++ if (!directory) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("tragedy: yaffs_FindObjectByName: null pointer directory"
++ TENDSTR)));
++ YBUG();
++ return NULL;
++ }
++ if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
++ YBUG();
++ }
++
++ sum = yaffs_CalcNameSum(name);
++
++ ylist_for_each(i, &directory->variant.directoryVariant.children) {
++ if (i) {
++ l = ylist_entry(i, yaffs_Object, siblings);
++
++ if (l->parent != directory)
++ YBUG();
++
++ yaffs_CheckObjectDetailsLoaded(l);
++
++ /* Special case for lost-n-found */
++ if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
++ if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0)
++ return l;
++ } else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0) {
++ /* LostnFound chunk called Objxxx
++ * Do a real check
++ */
++ yaffs_GetObjectName(l, buffer,
++ YAFFS_MAX_NAME_LENGTH + 1);
++ if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
++ return l;
++ }
++ }
++ }
++
++ return NULL;
++}
++
++
++#if 0
++int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,
++ int (*fn) (yaffs_Object *))
++{
++ struct ylist_head *i;
++ yaffs_Object *l;
++
++ if (!theDir) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("tragedy: yaffs_FindObjectByName: null pointer directory"
++ TENDSTR)));
++ YBUG();
++ return YAFFS_FAIL;
++ }
++ if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
++ YBUG();
++ return YAFFS_FAIL;
++ }
++
++ ylist_for_each(i, &theDir->variant.directoryVariant.children) {
++ if (i) {
++ l = ylist_entry(i, yaffs_Object, siblings);
++ if (l && !fn(l))
++ return YAFFS_FAIL;
++ }
++ }
++
++ return YAFFS_OK;
++
++}
++#endif
++
++/* GetEquivalentObject dereferences any hard links to get to the
++ * actual object.
++ */
++
++yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
++{
++ if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
++ /* We want the object id of the equivalent object, not this one */
++ obj = obj->variant.hardLinkVariant.equivalentObject;
++ yaffs_CheckObjectDetailsLoaded(obj);
++ }
++ return obj;
++}
++
++int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)
++{
++ memset(name, 0, buffSize * sizeof(YCHAR));
++
++ yaffs_CheckObjectDetailsLoaded(obj);
++
++ if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
++ yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
++ } else if (obj->hdrChunk <= 0) {
++ YCHAR locName[20];
++ YCHAR numString[20];
++ YCHAR *x = &numString[19];
++ unsigned v = obj->objectId;
++ numString[19] = 0;
++ while (v > 0) {
++ x--;
++ *x = '0' + (v % 10);
++ v /= 10;
++ }
++ /* make up a name */
++ yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
++ yaffs_strcat(locName, x);
++ yaffs_strncpy(name, locName, buffSize - 1);
++
++ }
++#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
++ else if (obj->shortName[0])
++ yaffs_strncpy(name, obj->shortName,YAFFS_SHORT_NAME_LENGTH+1);
++#endif
++ else {
++ int result;
++ __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
++
++ yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer;
++
++ memset(buffer, 0, obj->myDev->nDataBytesPerChunk);
++
++ if (obj->hdrChunk > 0) {
++ result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev,
++ obj->hdrChunk, buffer,
++ NULL);
++ }
++ yaffs_strncpy(name, oh->name, buffSize - 1);
++ name[buffSize-1]=0;
++
++ yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
++ }
++
++ return yaffs_strnlen(name,buffSize-1);
++}
++
++int yaffs_GetObjectFileLength(yaffs_Object *obj)
++{
++ /* Dereference any hard linking */
++ obj = yaffs_GetEquivalentObject(obj);
++
++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
++ return obj->variant.fileVariant.fileSize;
++ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK){
++ if(!obj->variant.symLinkVariant.alias)
++ return 0;
++ return yaffs_strnlen(obj->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
++ } else {
++ /* Only a directory should drop through to here */
++ return obj->myDev->nDataBytesPerChunk;
++ }
++}
++
++int yaffs_GetObjectLinkCount(yaffs_Object *obj)
++{
++ int count = 0;
++ struct ylist_head *i;
++
++ if (!obj->unlinked)
++ count++; /* the object itself */
++
++ ylist_for_each(i, &obj->hardLinks)
++ count++; /* add the hard links; */
++
++ return count;
++}
++
++int yaffs_GetObjectInode(yaffs_Object *obj)
++{
++ obj = yaffs_GetEquivalentObject(obj);
++
++ return obj->objectId;
++}
++
++unsigned yaffs_GetObjectType(yaffs_Object *obj)
++{
++ obj = yaffs_GetEquivalentObject(obj);
++
++ switch (obj->variantType) {
++ case YAFFS_OBJECT_TYPE_FILE:
++ return DT_REG;
++ break;
++ case YAFFS_OBJECT_TYPE_DIRECTORY:
++ return DT_DIR;
++ break;
++ case YAFFS_OBJECT_TYPE_SYMLINK:
++ return DT_LNK;
++ break;
++ case YAFFS_OBJECT_TYPE_HARDLINK:
++ return DT_REG;
++ break;
++ case YAFFS_OBJECT_TYPE_SPECIAL:
++ if (S_ISFIFO(obj->yst_mode))
++ return DT_FIFO;
++ if (S_ISCHR(obj->yst_mode))
++ return DT_CHR;
++ if (S_ISBLK(obj->yst_mode))
++ return DT_BLK;
++ if (S_ISSOCK(obj->yst_mode))
++ return DT_SOCK;
++ default:
++ return DT_REG;
++ break;
++ }
++}
++
++YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)
++{
++ obj = yaffs_GetEquivalentObject(obj);
++ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
++ return yaffs_CloneString(obj->variant.symLinkVariant.alias);
++ else
++ return yaffs_CloneString(_Y(""));
++}
++
++#ifndef CONFIG_YAFFS_WINCE
++
++int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
++{
++ unsigned int valid = attr->ia_valid;
++
++ if (valid & ATTR_MODE)
++ obj->yst_mode = attr->ia_mode;
++ if (valid & ATTR_UID)
++ obj->yst_uid = attr->ia_uid;
++ if (valid & ATTR_GID)
++ obj->yst_gid = attr->ia_gid;
++
++ if (valid & ATTR_ATIME)
++ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
++ if (valid & ATTR_CTIME)
++ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
++ if (valid & ATTR_MTIME)
++ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
++
++ if (valid & ATTR_SIZE)
++ yaffs_ResizeFile(obj, attr->ia_size);
++
++ yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
++
++ return YAFFS_OK;
++
++}
++int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
++{
++ unsigned int valid = 0;
++
++ attr->ia_mode = obj->yst_mode;
++ valid |= ATTR_MODE;
++ attr->ia_uid = obj->yst_uid;
++ valid |= ATTR_UID;
++ attr->ia_gid = obj->yst_gid;
++ valid |= ATTR_GID;
++
++ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
++ valid |= ATTR_ATIME;
++ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
++ valid |= ATTR_CTIME;
++ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
++ valid |= ATTR_MTIME;
++
++ attr->ia_size = yaffs_GetFileSize(obj);
++ valid |= ATTR_SIZE;
++
++ attr->ia_valid = valid;
++
++ return YAFFS_OK;
++}
++
++#endif
++
++#if 0
++int yaffs_DumpObject(yaffs_Object *obj)
++{
++ YCHAR name[257];
++
++ yaffs_GetObjectName(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
++
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d"
++ " chunk %d type %d size %d\n"
++ TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name,
++ obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk,
++ yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
++
++ return YAFFS_OK;
++}
++#endif
++
++/*---------------------------- Initialisation code -------------------------------------- */
++
++static int yaffs_CheckDevFunctions(const yaffs_Device *dev)
++{
++
++ /* Common functions, gotta have */
++ if (!dev->eraseBlockInNAND || !dev->initialiseNAND)
++ return 0;
++
++#ifdef CONFIG_YAFFS_YAFFS2
++
++ /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
++ if (dev->writeChunkWithTagsToNAND &&
++ dev->readChunkWithTagsFromNAND &&
++ !dev->writeChunkToNAND &&
++ !dev->readChunkFromNAND &&
++ dev->markNANDBlockBad && dev->queryNANDBlock)
++ return 1;
++#endif
++
++ /* Can use the "spare" style interface for yaffs1 */
++ if (!dev->isYaffs2 &&
++ !dev->writeChunkWithTagsToNAND &&
++ !dev->readChunkWithTagsFromNAND &&
++ dev->writeChunkToNAND &&
++ dev->readChunkFromNAND &&
++ !dev->markNANDBlockBad && !dev->queryNANDBlock)
++ return 1;
++
++ return 0; /* bad */
++}
++
++
++static int yaffs_CreateInitialDirectories(yaffs_Device *dev)
++{
++ /* Initialise the unlinked, deleted, root and lost and found directories */
++
++ dev->lostNFoundDir = dev->rootDir = NULL;
++ dev->unlinkedDir = dev->deletedDir = NULL;
++
++ dev->unlinkedDir =
++ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
++
++ dev->deletedDir =
++ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
++
++ dev->rootDir =
++ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT,
++ YAFFS_ROOT_MODE | S_IFDIR);
++ dev->lostNFoundDir =
++ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND,
++ YAFFS_LOSTNFOUND_MODE | S_IFDIR);
++
++ if (dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir) {
++ yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir);
++ return YAFFS_OK;
++ }
++
++ return YAFFS_FAIL;
++}
++
++int yaffs_GutsInitialise(yaffs_Device *dev)
++{
++ int init_failed = 0;
++ unsigned x;
++ int bits;
++
++ T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
++
++ /* Check stuff that must be set */
++
++ if (!dev) {
++ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Need a device" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ dev->internalStartBlock = dev->startBlock;
++ dev->internalEndBlock = dev->endBlock;
++ dev->blockOffset = 0;
++ dev->chunkOffset = 0;
++ dev->nFreeChunks = 0;
++
++ dev->gcBlock = -1;
++
++ if (dev->startBlock == 0) {
++ dev->internalStartBlock = dev->startBlock + 1;
++ dev->internalEndBlock = dev->endBlock + 1;
++ dev->blockOffset = 1;
++ dev->chunkOffset = dev->nChunksPerBlock;
++ }
++
++ /* Check geometry parameters. */
++
++ if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) ||
++ (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) ||
++ (dev->inbandTags && !dev->isYaffs2) ||
++ dev->nChunksPerBlock < 2 ||
++ dev->nReservedBlocks < 2 ||
++ dev->internalStartBlock <= 0 ||
++ dev->internalEndBlock <= 0 ||
++ dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) { /* otherwise it is too small */
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d "
++ TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags));
++ return YAFFS_FAIL;
++ }
++
++ if (yaffs_InitialiseNAND(dev) != YAFFS_OK) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ /* Sort out space for inband tags, if required */
++ if (dev->inbandTags)
++ dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
++ else
++ dev->nDataBytesPerChunk = dev->totalBytesPerChunk;
++
++ /* Got the right mix of functions? */
++ if (!yaffs_CheckDevFunctions(dev)) {
++ /* Function missing */
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR
++ ("yaffs: device function(s) missing or wrong\n" TENDSTR)));
++
++ return YAFFS_FAIL;
++ }
++
++ /* This is really a compilation check. */
++ if (!yaffs_CheckStructures()) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ if (dev->isMounted) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: device already mounted\n" TENDSTR)));
++ return YAFFS_FAIL;
++ }
++
++ /* Finished with most checks. One or two more checks happen later on too. */
++
++ dev->isMounted = 1;
++
++ /* OK now calculate a few things for the device */
++
++ /*
++ * Calculate all the chunk size manipulation numbers:
++ */
++ x = dev->nDataBytesPerChunk;
++ /* We always use dev->chunkShift and dev->chunkDiv */
++ dev->chunkShift = Shifts(x);
++ x >>= dev->chunkShift;
++ dev->chunkDiv = x;
++ /* We only use chunk mask if chunkDiv is 1 */
++ dev->chunkMask = (1<<dev->chunkShift) - 1;
++
++ /*
++ * Calculate chunkGroupBits.
++ * We need to find the next power of 2 > than internalEndBlock
++ */
++
++ x = dev->nChunksPerBlock * (dev->internalEndBlock + 1);
++
++ bits = ShiftsGE(x);
++
++ /* Set up tnode width if wide tnodes are enabled. */
++ if (!dev->wideTnodesDisabled) {
++ /* bits must be even so that we end up with 32-bit words */
++ if (bits & 1)
++ bits++;
++ if (bits < 16)
++ dev->tnodeWidth = 16;
++ else
++ dev->tnodeWidth = bits;
++ } else
++ dev->tnodeWidth = 16;
++
++ dev->tnodeMask = (1<<dev->tnodeWidth)-1;
++
++ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
++ * so if the bitwidth of the
++ * chunk range we're using is greater than 16 we need
++ * to figure out chunk shift and chunkGroupSize
++ */
++
++ if (bits <= dev->tnodeWidth)
++ dev->chunkGroupBits = 0;
++ else
++ dev->chunkGroupBits = bits - dev->tnodeWidth;
++
++
++ dev->chunkGroupSize = 1 << dev->chunkGroupBits;
++
++ if (dev->nChunksPerBlock < dev->chunkGroupSize) {
++ /* We have a problem because the soft delete won't work if
++ * the chunk group size > chunks per block.
++ * This can be remedied by using larger "virtual blocks".
++ */
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: chunk group too large\n" TENDSTR)));
++
++ return YAFFS_FAIL;
++ }
++
++ /* OK, we've finished verifying the device, lets continue with initialisation */
++
++ /* More device initialisation */
++ dev->garbageCollections = 0;
++ dev->passiveGarbageCollections = 0;
++ dev->currentDirtyChecker = 0;
++ dev->bufferedBlock = -1;
++ dev->doingBufferedBlockRewrite = 0;
++ dev->nDeletedFiles = 0;
++ dev->nBackgroundDeletions = 0;
++ dev->nUnlinkedFiles = 0;
++ dev->eccFixed = 0;
++ dev->eccUnfixed = 0;
++ dev->tagsEccFixed = 0;
++ dev->tagsEccUnfixed = 0;
++ dev->nErasureFailures = 0;
++ dev->nErasedBlocks = 0;
++ dev->isDoingGC = 0;
++ dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */
++
++ /* Initialise temporary buffers and caches. */
++ if (!yaffs_InitialiseTempBuffers(dev))
++ init_failed = 1;
++
++ dev->srCache = NULL;
++ dev->gcCleanupList = NULL;
++
++
++ if (!init_failed &&
++ dev->nShortOpCaches > 0) {
++ int i;
++ void *buf;
++ int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);
++
++ if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
++ dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
++
++ dev->srCache = YMALLOC(srCacheBytes);
++
++ buf = (__u8 *) dev->srCache;
++
++ if (dev->srCache)
++ memset(dev->srCache, 0, srCacheBytes);
++
++ for (i = 0; i < dev->nShortOpCaches && buf; i++) {
++ dev->srCache[i].object = NULL;
++ dev->srCache[i].lastUse = 0;
++ dev->srCache[i].dirty = 0;
++ dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk);
++ }
++ if (!buf)
++ init_failed = 1;
++
++ dev->srLastUse = 0;
++ }
++
++ dev->cacheHits = 0;
++
++ if (!init_failed) {
++ dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
++ if (!dev->gcCleanupList)
++ init_failed = 1;
++ }
++
++ if (dev->isYaffs2)
++ dev->useHeaderFileSize = 1;
++
++ if (!init_failed && !yaffs_InitialiseBlocks(dev))
++ init_failed = 1;
++
++ yaffs_InitialiseTnodes(dev);
++ yaffs_InitialiseObjects(dev);
++
++ if (!init_failed && !yaffs_CreateInitialDirectories(dev))
++ init_failed = 1;
++
++
++ if (!init_failed) {
++ /* Now scan the flash. */
++ if (dev->isYaffs2) {
++ if (yaffs_CheckpointRestore(dev)) {
++ yaffs_CheckObjectDetailsLoaded(dev->rootDir);
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("yaffs: restored from checkpoint" TENDSTR)));
++ } else {
++
++ /* Clean up the mess caused by an aborted checkpoint load
++ * and scan backwards.
++ */
++ yaffs_DeinitialiseBlocks(dev);
++ yaffs_DeinitialiseTnodes(dev);
++ yaffs_DeinitialiseObjects(dev);
++
++
++ dev->nErasedBlocks = 0;
++ dev->nFreeChunks = 0;
++ dev->allocationBlock = -1;
++ dev->allocationPage = -1;
++ dev->nDeletedFiles = 0;
++ dev->nUnlinkedFiles = 0;
++ dev->nBackgroundDeletions = 0;
++ dev->oldestDirtySequence = 0;
++
++ if (!init_failed && !yaffs_InitialiseBlocks(dev))
++ init_failed = 1;
++
++ yaffs_InitialiseTnodes(dev);
++ yaffs_InitialiseObjects(dev);
++
++ if (!init_failed && !yaffs_CreateInitialDirectories(dev))
++ init_failed = 1;
++
++ if (!init_failed && !yaffs_ScanBackwards(dev))
++ init_failed = 1;
++ }
++ } else if (!yaffs_Scan(dev))
++ init_failed = 1;
++
++ yaffs_StripDeletedObjects(dev);
++ yaffs_FixHangingObjects(dev);
++ if(dev->emptyLostAndFound)
++ yaffs_EmptyLostAndFound(dev);
++ }
++
++ if (init_failed) {
++ /* Clean up the mess */
++ T(YAFFS_TRACE_TRACING,
++ (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR)));
++
++ yaffs_Deinitialise(dev);
++ return YAFFS_FAIL;
++ }
++
++ /* Zero out stats */
++ dev->nPageReads = 0;
++ dev->nPageWrites = 0;
++ dev->nBlockErasures = 0;
++ dev->nGCCopies = 0;
++ dev->nRetriedWrites = 0;
++
++ dev->nRetiredBlocks = 0;
++
++ yaffs_VerifyFreeChunks(dev);
++ yaffs_VerifyBlocks(dev);
++
++ /* Clean up any aborted checkpoint data */
++ if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
++ yaffs_InvalidateCheckpoint(dev);
++
++ T(YAFFS_TRACE_TRACING,
++ (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
++ return YAFFS_OK;
++
++}
++
++void yaffs_Deinitialise(yaffs_Device *dev)
++{
++ if (dev->isMounted) {
++ int i;
++
++ yaffs_DeinitialiseBlocks(dev);
++ yaffs_DeinitialiseTnodes(dev);
++ yaffs_DeinitialiseObjects(dev);
++ if (dev->nShortOpCaches > 0 &&
++ dev->srCache) {
++
++ for (i = 0; i < dev->nShortOpCaches; i++) {
++ if (dev->srCache[i].data)
++ YFREE(dev->srCache[i].data);
++ dev->srCache[i].data = NULL;
++ }
++
++ YFREE(dev->srCache);
++ dev->srCache = NULL;
++ }
++
++ YFREE(dev->gcCleanupList);
++
++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
++ YFREE(dev->tempBuffer[i].buffer);
++
++ dev->isMounted = 0;
++
++ if (dev->deinitialiseNAND)
++ dev->deinitialiseNAND(dev);
++ }
++}
++
++static int yaffs_CountFreeChunks(yaffs_Device *dev)
++{
++ int nFree;
++ int b;
++
++ yaffs_BlockInfo *blk;
++
++ for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
++ b++) {
++ blk = yaffs_GetBlockInfo(dev, b);
++
++ switch (blk->blockState) {
++ case YAFFS_BLOCK_STATE_EMPTY:
++ case YAFFS_BLOCK_STATE_ALLOCATING:
++ case YAFFS_BLOCK_STATE_COLLECTING:
++ case YAFFS_BLOCK_STATE_FULL:
++ nFree +=
++ (dev->nChunksPerBlock - blk->pagesInUse +
++ blk->softDeletions);
++ break;
++ default:
++ break;
++ }
++ }
++
++ return nFree;
++}
++
++int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
++{
++ /* This is what we report to the outside world */
++
++ int nFree;
++ int nDirtyCacheChunks;
++ int blocksForCheckpoint;
++ int i;
++
++#if 1
++ nFree = dev->nFreeChunks;
++#else
++ nFree = yaffs_CountFreeChunks(dev);
++#endif
++
++ nFree += dev->nDeletedFiles;
++
++ /* Now count the number of dirty chunks in the cache and subtract those */
++
++ for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
++ if (dev->srCache[i].dirty)
++ nDirtyCacheChunks++;
++ }
++
++ nFree -= nDirtyCacheChunks;
++
++ nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
++
++ /* Now we figure out how much to reserve for the checkpoint and report that... */
++ blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
++ if (blocksForCheckpoint < 0)
++ blocksForCheckpoint = 0;
++
++ nFree -= (blocksForCheckpoint * dev->nChunksPerBlock);
++
++ if (nFree < 0)
++ nFree = 0;
++
++ return nFree;
++
++}
++
++static int yaffs_freeVerificationFailures;
++
++static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
++{
++ int counted;
++ int difference;
++
++ if (yaffs_SkipVerification(dev))
++ return;
++
++ counted = yaffs_CountFreeChunks(dev);
++
++ difference = dev->nFreeChunks - counted;
++
++ if (difference) {
++ T(YAFFS_TRACE_ALWAYS,
++ (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
++ dev->nFreeChunks, counted, difference));
++ yaffs_freeVerificationFailures++;
++ }
++}
++
++/*---------------------------------------- YAFFS test code ----------------------*/
++
++#define yaffs_CheckStruct(structure, syze, name) \
++ do { \
++ if (sizeof(structure) != syze) { \
++ T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
++ name, syze, (int) sizeof(structure))); \
++ return YAFFS_FAIL; \
++ } \
++ } while (0)
++
++static int yaffs_CheckStructures(void)
++{
++/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */
++/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */
++/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */
++#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
++/* yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); */
++#endif
++#ifndef CONFIG_YAFFS_WINCE
++ yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");
++#endif
++ return YAFFS_OK;
++}
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_guts.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_guts.h
+--- linux-2.6.29/fs/yaffs2/yaffs_guts.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_guts.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,912 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GUTS_H__
++#define __YAFFS_GUTS_H__
++
++#include "devextras.h"
++#include "yportenv.h"
++
++#define YAFFS_OK 1
++#define YAFFS_FAIL 0
++
++/* Give us a Y=0x59,
++ * Give us an A=0x41,
++ * Give us an FF=0xFF
++ * Give us an S=0x53
++ * And what have we got...
++ */
++#define YAFFS_MAGIC 0x5941FF53
++
++#define YAFFS_NTNODES_LEVEL0 16
++#define YAFFS_TNODES_LEVEL0_BITS 4
++#define YAFFS_TNODES_LEVEL0_MASK 0xf
++
++#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
++#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
++#define YAFFS_TNODES_INTERNAL_MASK 0x7
++#define YAFFS_TNODES_MAX_LEVEL 6
++
++#ifndef CONFIG_YAFFS_NO_YAFFS1
++#define YAFFS_BYTES_PER_SPARE 16
++#define YAFFS_BYTES_PER_CHUNK 512
++#define YAFFS_CHUNK_SIZE_SHIFT 9
++#define YAFFS_CHUNKS_PER_BLOCK 32
++#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
++#endif
++
++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
++#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
++
++#define YAFFS_MAX_CHUNK_ID 0x000FFFFF
++
++#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
++
++#define YAFFS_ALLOCATION_NOBJECTS 100
++#define YAFFS_ALLOCATION_NTNODES 100
++#define YAFFS_ALLOCATION_NLINKS 100
++
++#define YAFFS_NOBJECT_BUCKETS 256
++
++
++#define YAFFS_OBJECT_SPACE 0x40000
++
++#define YAFFS_CHECKPOINT_VERSION 3
++
++#ifdef CONFIG_YAFFS_UNICODE
++#define YAFFS_MAX_NAME_LENGTH 127
++#define YAFFS_MAX_ALIAS_LENGTH 79
++#else
++#define YAFFS_MAX_NAME_LENGTH 255
++#define YAFFS_MAX_ALIAS_LENGTH 159
++#endif
++
++#define YAFFS_SHORT_NAME_LENGTH 15
++
++/* Some special object ids for pseudo objects */
++#define YAFFS_OBJECTID_ROOT 1
++#define YAFFS_OBJECTID_LOSTNFOUND 2
++#define YAFFS_OBJECTID_UNLINKED 3
++#define YAFFS_OBJECTID_DELETED 4
++
++/* Sseudo object ids for checkpointing */
++#define YAFFS_OBJECTID_SB_HEADER 0x10
++#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
++#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
++
++/* */
++
++#define YAFFS_MAX_SHORT_OP_CACHES 20
++
++#define YAFFS_N_TEMP_BUFFERS 6
++
++/* We limit the number attempts at sucessfully saving a chunk of data.
++ * Small-page devices have 32 pages per block; large-page devices have 64.
++ * Default to something in the order of 5 to 10 blocks worth of chunks.
++ */
++#define YAFFS_WR_ATTEMPTS (5*64)
++
++/* Sequence numbers are used in YAFFS2 to determine block allocation order.
++ * The range is limited slightly to help distinguish bad numbers from good.
++ * This also allows us to perhaps in the future use special numbers for
++ * special purposes.
++ * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,
++ * and is a larger number than the lifetime of a 2GB device.
++ */
++#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
++#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00
++
++/* Special sequence number for bad block that failed to be marked bad */
++#define YAFFS_SEQUENCE_BAD_BLOCK 0xFFFF0000
++
++/* ChunkCache is used for short read/write operations.*/
++typedef struct {
++ struct yaffs_ObjectStruct *object;
++ int chunkId;
++ int lastUse;
++ int dirty;
++ int nBytes; /* Only valid if the cache is dirty */
++ int locked; /* Can't push out or flush while locked. */
++#ifdef CONFIG_YAFFS_YAFFS2
++ __u8 *data;
++#else
++ __u8 data[YAFFS_BYTES_PER_CHUNK];
++#endif
++} yaffs_ChunkCache;
++
++
++
++/* Tags structures in RAM
++ * NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
++ * the structure size will get blown out.
++ */
++
++#ifndef CONFIG_YAFFS_NO_YAFFS1
++typedef struct {
++ unsigned chunkId:20;
++ unsigned serialNumber:2;
++ unsigned byteCountLSB:10;
++ unsigned objectId:18;
++ unsigned ecc:12;
++ unsigned byteCountMSB:2;
++} yaffs_Tags;
++
++typedef union {
++ yaffs_Tags asTags;
++ __u8 asBytes[8];
++} yaffs_TagsUnion;
++
++#endif
++
++/* Stuff used for extended tags in YAFFS2 */
++
++typedef enum {
++ YAFFS_ECC_RESULT_UNKNOWN,
++ YAFFS_ECC_RESULT_NO_ERROR,
++ YAFFS_ECC_RESULT_FIXED,
++ YAFFS_ECC_RESULT_UNFIXED
++} yaffs_ECCResult;
++
++typedef enum {
++ YAFFS_OBJECT_TYPE_UNKNOWN,
++ YAFFS_OBJECT_TYPE_FILE,
++ YAFFS_OBJECT_TYPE_SYMLINK,
++ YAFFS_OBJECT_TYPE_DIRECTORY,
++ YAFFS_OBJECT_TYPE_HARDLINK,
++ YAFFS_OBJECT_TYPE_SPECIAL
++} yaffs_ObjectType;
++
++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
++
++typedef struct {
++
++ unsigned validMarker0;
++ unsigned chunkUsed; /* Status of the chunk: used or unused */
++ unsigned objectId; /* If 0 then this is not part of an object (unused) */
++ unsigned chunkId; /* If 0 then this is a header, else a data chunk */
++ unsigned byteCount; /* Only valid for data chunks */
++
++ /* The following stuff only has meaning when we read */
++ yaffs_ECCResult eccResult;
++ unsigned blockBad;
++
++ /* YAFFS 1 stuff */
++ unsigned chunkDeleted; /* The chunk is marked deleted */
++ unsigned serialNumber; /* Yaffs1 2-bit serial number */
++
++ /* YAFFS2 stuff */
++ unsigned sequenceNumber; /* The sequence number of this block */
++
++ /* Extra info if this is an object header (YAFFS2 only) */
++
++ unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */
++ unsigned extraParentObjectId; /* The parent object */
++ unsigned extraIsShrinkHeader; /* Is it a shrink header? */
++ unsigned extraShadows; /* Does this shadow another object? */
++
++ yaffs_ObjectType extraObjectType; /* What object type? */
++
++ unsigned extraFileLength; /* Length if it is a file */
++ unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */
++
++ unsigned validMarker1;
++
++} yaffs_ExtendedTags;
++
++/* Spare structure for YAFFS1 */
++typedef struct {
++ __u8 tagByte0;
++ __u8 tagByte1;
++ __u8 tagByte2;
++ __u8 tagByte3;
++ __u8 pageStatus; /* set to 0 to delete the chunk */
++ __u8 blockStatus;
++ __u8 tagByte4;
++ __u8 tagByte5;
++ __u8 ecc1[3];
++ __u8 tagByte6;
++ __u8 tagByte7;
++ __u8 ecc2[3];
++} yaffs_Spare;
++
++/*Special structure for passing through to mtd */
++struct yaffs_NANDSpare {
++ yaffs_Spare spare;
++ int eccres1;
++ int eccres2;
++};
++
++/* Block data in RAM */
++
++typedef enum {
++ YAFFS_BLOCK_STATE_UNKNOWN = 0,
++
++ YAFFS_BLOCK_STATE_SCANNING,
++ YAFFS_BLOCK_STATE_NEEDS_SCANNING,
++ /* The block might have something on it (ie it is allocating or full, perhaps empty)
++ * but it needs to be scanned to determine its true state.
++ * This state is only valid during yaffs_Scan.
++ * NB We tolerate empty because the pre-scanner might be incapable of deciding
++ * However, if this state is returned on a YAFFS2 device, then we expect a sequence number
++ */
++
++ YAFFS_BLOCK_STATE_EMPTY,
++ /* This block is empty */
++
++ YAFFS_BLOCK_STATE_ALLOCATING,
++ /* This block is partially allocated.
++ * At least one page holds valid data.
++ * This is the one currently being used for page
++ * allocation. Should never be more than one of these
++ */
++
++ YAFFS_BLOCK_STATE_FULL,
++ /* All the pages in this block have been allocated.
++ */
++
++ YAFFS_BLOCK_STATE_DIRTY,
++ /* All pages have been allocated and deleted.
++ * Erase me, reuse me.
++ */
++
++ YAFFS_BLOCK_STATE_CHECKPOINT,
++ /* This block is assigned to holding checkpoint data.
++ */
++
++ YAFFS_BLOCK_STATE_COLLECTING,
++ /* This block is being garbage collected */
++
++ YAFFS_BLOCK_STATE_DEAD
++ /* This block has failed and is not in use */
++} yaffs_BlockState;
++
++#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
++
++
++typedef struct {
++
++ int softDeletions:10; /* number of soft deleted pages */
++ int pagesInUse:10; /* number of pages in use */
++ unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
++ __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
++ /* and retire the block. */
++ __u32 skipErasedCheck:1; /* If this is set we can skip the erased check on this block */
++ __u32 gcPrioritise:1; /* An ECC check or blank check has failed on this block.
++ It should be prioritised for GC */
++ __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
++
++#ifdef CONFIG_YAFFS_YAFFS2
++ __u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
++ __u32 sequenceNumber; /* block sequence number for yaffs2 */
++#endif
++
++} yaffs_BlockInfo;
++
++/* -------------------------- Object structure -------------------------------*/
++/* This is the object structure as stored on NAND */
++
++typedef struct {
++ yaffs_ObjectType type;
++
++ /* Apply to everything */
++ int parentObjectId;
++ __u16 sum__NoLongerUsed; /* checksum of name. No longer used */
++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
++
++ /* The following apply to directories, files, symlinks - not hard links */
++ __u32 yst_mode; /* protection */
++
++#ifdef CONFIG_YAFFS_WINCE
++ __u32 notForWinCE[5];
++#else
++ __u32 yst_uid;
++ __u32 yst_gid;
++ __u32 yst_atime;
++ __u32 yst_mtime;
++ __u32 yst_ctime;
++#endif
++
++ /* File size applies to files only */
++ int fileSize;
++
++ /* Equivalent object id applies to hard links only. */
++ int equivalentObjectId;
++
++ /* Alias is for symlinks only. */
++ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
++
++ __u32 yst_rdev; /* device stuff for block and char devices (major/min) */
++
++#ifdef CONFIG_YAFFS_WINCE
++ __u32 win_ctime[2];
++ __u32 win_atime[2];
++ __u32 win_mtime[2];
++#else
++ __u32 roomToGrow[6];
++
++#endif
++ __u32 inbandShadowsObject;
++ __u32 inbandIsShrink;
++
++ __u32 reservedSpace[2];
++ int shadowsObject; /* This object header shadows the specified object if > 0 */
++
++ /* isShrink applies to object headers written when we shrink the file (ie resize) */
++ __u32 isShrink;
++
++} yaffs_ObjectHeader;
++
++/*--------------------------- Tnode -------------------------- */
++
++union yaffs_Tnode_union {
++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
++ union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
++#else
++ union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
++#endif
++/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
++
++};
++
++typedef union yaffs_Tnode_union yaffs_Tnode;
++
++struct yaffs_TnodeList_struct {
++ struct yaffs_TnodeList_struct *next;
++ yaffs_Tnode *tnodes;
++};
++
++typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
++
++/*------------------------ Object -----------------------------*/
++/* An object can be one of:
++ * - a directory (no data, has children links
++ * - a regular file (data.... not prunes :->).
++ * - a symlink [symbolic link] (the alias).
++ * - a hard link
++ */
++
++typedef struct {
++ __u32 fileSize;
++ __u32 scannedFileSize;
++ __u32 shrinkSize;
++ int topLevel;
++ yaffs_Tnode *top;
++} yaffs_FileStructure;
++
++typedef struct {
++ struct ylist_head children; /* list of child links */
++} yaffs_DirectoryStructure;
++
++typedef struct {
++ YCHAR *alias;
++} yaffs_SymLinkStructure;
++
++typedef struct {
++ struct yaffs_ObjectStruct *equivalentObject;
++ __u32 equivalentObjectId;
++} yaffs_HardLinkStructure;
++
++typedef union {
++ yaffs_FileStructure fileVariant;
++ yaffs_DirectoryStructure directoryVariant;
++ yaffs_SymLinkStructure symLinkVariant;
++ yaffs_HardLinkStructure hardLinkVariant;
++} yaffs_ObjectVariant;
++
++
++
++struct yaffs_ObjectStruct {
++ __u8 deleted:1; /* This should only apply to unlinked files. */
++ __u8 softDeleted:1; /* it has also been soft deleted */
++ __u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/
++ __u8 fake:1; /* A fake object has no presence on NAND. */
++ __u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */
++ __u8 unlinkAllowed:1;
++ __u8 dirty:1; /* the object needs to be written to flash */
++ __u8 valid:1; /* When the file system is being loaded up, this
++ * object might be created before the data
++ * is available (ie. file data records appear before the header).
++ */
++ __u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */
++
++ __u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is
++ * still in the inode cache. Free of object is defered.
++ * until the inode is released.
++ */
++ __u8 beingCreated:1; /* This object is still being created so skip some checks. */
++ __u8 isShadowed:1; /* This object is shadowed on the way to being renamed. */
++
++ __u8 serial; /* serial number of chunk in NAND. Cached here */
++ __u16 sum; /* sum of the name to speed searching */
++
++ struct yaffs_DeviceStruct *myDev; /* The device I'm on */
++
++ struct ylist_head hashLink; /* list of objects in this hash bucket */
++
++ struct ylist_head hardLinks; /* all the equivalent hard linked objects */
++
++ /* directory structure stuff */
++ /* also used for linking up the free list */
++ struct yaffs_ObjectStruct *parent;
++ struct ylist_head siblings;
++
++ /* Where's my object header in NAND? */
++ int hdrChunk;
++
++ int nDataChunks; /* Number of data chunks attached to the file. */
++
++ __u32 objectId; /* the object id value */
++
++ __u32 yst_mode;
++
++#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
++ YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
++#endif
++
++#ifdef CONFIG_YAFFS_WINCE
++ __u32 win_ctime[2];
++ __u32 win_mtime[2];
++ __u32 win_atime[2];
++#else
++ __u32 yst_uid;
++ __u32 yst_gid;
++ __u32 yst_atime;
++ __u32 yst_mtime;
++ __u32 yst_ctime;
++#endif
++
++ __u32 yst_rdev;
++
++ void *myInode;
++
++ yaffs_ObjectType variantType;
++
++ yaffs_ObjectVariant variant;
++
++};
++
++typedef struct yaffs_ObjectStruct yaffs_Object;
++
++struct yaffs_ObjectList_struct {
++ yaffs_Object *objects;
++ struct yaffs_ObjectList_struct *next;
++};
++
++typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
++
++typedef struct {
++ struct ylist_head list;
++ int count;
++} yaffs_ObjectBucket;
++
++
++/* yaffs_CheckpointObject holds the definition of an object as dumped
++ * by checkpointing.
++ */
++
++typedef struct {
++ int structType;
++ __u32 objectId;
++ __u32 parentId;
++ int hdrChunk;
++ yaffs_ObjectType variantType:3;
++ __u8 deleted:1;
++ __u8 softDeleted:1;
++ __u8 unlinked:1;
++ __u8 fake:1;
++ __u8 renameAllowed:1;
++ __u8 unlinkAllowed:1;
++ __u8 serial;
++
++ int nDataChunks;
++ __u32 fileSizeOrEquivalentObjectId;
++} yaffs_CheckpointObject;
++
++/*--------------------- Temporary buffers ----------------
++ *
++ * These are chunk-sized working buffers. Each device has a few
++ */
++
++typedef struct {
++ __u8 *buffer;
++ int line; /* track from whence this buffer was allocated */
++ int maxLine;
++} yaffs_TempBuffer;
++
++/*----------------- Device ---------------------------------*/
++
++
++struct yaffs_DeviceStruct {
++ struct ylist_head devList;
++ const char *name;
++
++ /* Entry parameters set up way early. Yaffs sets up the rest.*/
++ int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
++ int nChunksPerBlock; /* does not need to be a power of 2 */
++ int spareBytesPerChunk; /* spare area size */
++ int startBlock; /* Start block we're allowed to use */
++ int endBlock; /* End block we're allowed to use */
++ int nReservedBlocks; /* We want this tuneable so that we can reduce */
++ /* reserved blocks on NOR and RAM. */
++
++
++ /* Stuff used by the shared space checkpointing mechanism */
++ /* If this value is zero, then this mechanism is disabled */
++
++/* int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */
++
++
++ int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
++ * the number of short op caches (don't use too many)
++ */
++
++ int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
++
++ int useNANDECC; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */
++ int noTagsECC; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */
++
++ int disableLazyLoad; /* Disable lazy loading on this device */
++
++ void *genericDevice; /* Pointer to device context
++ * On an mtd this holds the mtd pointer.
++ */
++ void *superBlock;
++
++ /* NAND access functions (Must be set before calling YAFFS)*/
++
++ int (*writeChunkToNAND) (struct yaffs_DeviceStruct *dev,
++ int chunkInNAND, const __u8 *data,
++ const yaffs_Spare *spare);
++ int (*readChunkFromNAND) (struct yaffs_DeviceStruct *dev,
++ int chunkInNAND, __u8 *data,
++ yaffs_Spare *spare);
++ int (*eraseBlockInNAND) (struct yaffs_DeviceStruct *dev,
++ int blockInNAND);
++ int (*initialiseNAND) (struct yaffs_DeviceStruct *dev);
++ int (*deinitialiseNAND) (struct yaffs_DeviceStruct *dev);
++
++#ifdef CONFIG_YAFFS_YAFFS2
++ int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct *dev,
++ int chunkInNAND, const __u8 *data,
++ const yaffs_ExtendedTags *tags);
++ int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct *dev,
++ int chunkInNAND, __u8 *data,
++ yaffs_ExtendedTags *tags);
++ int (*markNANDBlockBad) (struct yaffs_DeviceStruct *dev, int blockNo);
++ int (*queryNANDBlock) (struct yaffs_DeviceStruct *dev, int blockNo,
++ yaffs_BlockState *state, __u32 *sequenceNumber);
++#endif
++
++ int isYaffs2;
++
++ /* The removeObjectCallback function must be supplied by OS flavours that
++ * need it.
++ * yaffs direct uses it to implement the faster readdir.
++ * Linux uses it to protect the directory during unlocking.
++ */
++ void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
++
++ /* Callback to mark the superblock dirsty */
++ void (*markSuperBlockDirty)(void *superblock);
++
++ int wideTnodesDisabled; /* Set to disable wide tnodes */
++
++ YCHAR *pathDividers; /* String of legal path dividers */
++
++
++ /* End of stuff that must be set before initialisation. */
++
++ /* Checkpoint control. Can be set before or after initialisation */
++ __u8 skipCheckpointRead;
++ __u8 skipCheckpointWrite;
++
++ /* Runtime parameters. Set up by YAFFS. */
++
++ __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
++ __u16 chunkGroupSize; /* == 2^^chunkGroupBits */
++
++ /* Stuff to support wide tnodes */
++ __u32 tnodeWidth;
++ __u32 tnodeMask;
++
++ /* Stuff for figuring out file offset to chunk conversions */
++ __u32 chunkShift; /* Shift value */
++ __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */
++ __u32 chunkMask; /* Mask to use for power-of-2 case */
++
++ /* Stuff to handle inband tags */
++ int inbandTags;
++ __u32 totalBytesPerChunk;
++
++#ifdef __KERNEL__
++
++ struct semaphore sem; /* Semaphore for waiting on erasure.*/
++ struct semaphore grossLock; /* Gross locking semaphore */
++ struct rw_semaphore dirLock; /* Lock the directory structure */
++ __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
++ * at compile time so we have to allocate it.
++
++ */
++ void (*putSuperFunc) (struct super_block *sb);
++ struct ylist_head searchContexts;
++
++#endif
++
++ int isMounted;
++
++ int isCheckpointed;
++
++
++ /* Stuff to support block offsetting to support start block zero */
++ int internalStartBlock;
++ int internalEndBlock;
++ int blockOffset;
++ int chunkOffset;
++
++
++ /* Runtime checkpointing stuff */
++ int checkpointPageSequence; /* running sequence number of checkpoint pages */
++ int checkpointByteCount;
++ int checkpointByteOffset;
++ __u8 *checkpointBuffer;
++ int checkpointOpenForWrite;
++ int blocksInCheckpoint;
++ int checkpointCurrentChunk;
++ int checkpointCurrentBlock;
++ int checkpointNextBlock;
++ int *checkpointBlockList;
++ int checkpointMaxBlocks;
++ __u32 checkpointSum;
++ __u32 checkpointXor;
++
++ int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */
++
++ /* Block Info */
++ yaffs_BlockInfo *blockInfo;
++ __u8 *chunkBits; /* bitmap of chunks in use */
++ unsigned blockInfoAlt:1; /* was allocated using alternative strategy */
++ unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */
++ int chunkBitmapStride; /* Number of bytes of chunkBits per block.
++ * Must be consistent with nChunksPerBlock.
++ */
++
++ int nErasedBlocks;
++ int allocationBlock; /* Current block being allocated off */
++ __u32 allocationPage;
++ int allocationBlockFinder; /* Used to search for next allocation block */
++
++ /* Runtime state */
++ int nTnodesCreated;
++ yaffs_Tnode *freeTnodes;
++ int nFreeTnodes;
++ yaffs_TnodeList *allocatedTnodeList;
++
++ int isDoingGC;
++ int gcBlock;
++ int gcChunk;
++
++ int nObjectsCreated;
++ yaffs_Object *freeObjects;
++ int nFreeObjects;
++
++ int nHardLinks;
++
++ yaffs_ObjectList *allocatedObjectList;
++
++ yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
++
++ int nFreeChunks;
++
++ int currentDirtyChecker; /* Used to find current dirtiest block */
++
++ __u32 *gcCleanupList; /* objects to delete at the end of a GC. */
++ int nonAggressiveSkip; /* GC state/mode */
++
++ /* Statistcs */
++ int nPageWrites;
++ int nPageReads;
++ int nBlockErasures;
++ int nErasureFailures;
++ int nGCCopies;
++ int garbageCollections;
++ int passiveGarbageCollections;
++ int nRetriedWrites;
++ int nRetiredBlocks;
++ int eccFixed;
++ int eccUnfixed;
++ int tagsEccFixed;
++ int tagsEccUnfixed;
++ int nDeletions;
++ int nUnmarkedDeletions;
++
++ int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
++
++ /* Special directories */
++ yaffs_Object *rootDir;
++ yaffs_Object *lostNFoundDir;
++
++ /* Buffer areas for storing data to recover from write failures TODO
++ * __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
++ * yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
++ */
++
++ int bufferedBlock; /* Which block is buffered here? */
++ int doingBufferedBlockRewrite;
++
++ yaffs_ChunkCache *srCache;
++ int srLastUse;
++
++ int cacheHits;
++
++ /* Stuff for background deletion and unlinked files.*/
++ yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
++ yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
++ yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/
++ int nDeletedFiles; /* Count of files awaiting deletion;*/
++ int nUnlinkedFiles; /* Count of unlinked files. */
++ int nBackgroundDeletions; /* Count of background deletions. */
++
++
++ /* Temporary buffer management */
++ yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
++ int maxTemp;
++ int tempInUse;
++ int unmanagedTempAllocations;
++ int unmanagedTempDeallocations;
++
++ /* yaffs2 runtime stuff */
++ unsigned sequenceNumber; /* Sequence number of currently allocating block */
++ unsigned oldestDirtySequence;
++
++ /* Auto empty lost and found directory on mount */
++ int emptyLostAndFound;
++};
++
++typedef struct yaffs_DeviceStruct yaffs_Device;
++
++/* The static layout of block usage etc is stored in the super block header */
++typedef struct {
++ int StructType;
++ int version;
++ int checkpointStartBlock;
++ int checkpointEndBlock;
++ int startBlock;
++ int endBlock;
++ int rfu[100];
++} yaffs_SuperBlockHeader;
++
++/* The CheckpointDevice structure holds the device information that changes at runtime and
++ * must be preserved over unmount/mount cycles.
++ */
++typedef struct {
++ int structType;
++ int nErasedBlocks;
++ int allocationBlock; /* Current block being allocated off */
++ __u32 allocationPage;
++ int nFreeChunks;
++
++ int nDeletedFiles; /* Count of files awaiting deletion;*/
++ int nUnlinkedFiles; /* Count of unlinked files. */
++ int nBackgroundDeletions; /* Count of background deletions. */
++
++ /* yaffs2 runtime stuff */
++ unsigned sequenceNumber; /* Sequence number of currently allocating block */
++ unsigned oldestDirtySequence;
++
++} yaffs_CheckpointDevice;
++
++
++typedef struct {
++ int structType;
++ __u32 magic;
++ __u32 version;
++ __u32 head;
++} yaffs_CheckpointValidity;
++
++
++/*----------------------- YAFFS Functions -----------------------*/
++
++int yaffs_GutsInitialise(yaffs_Device *dev);
++void yaffs_Deinitialise(yaffs_Device *dev);
++
++int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev);
++
++int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
++ yaffs_Object *newDir, const YCHAR *newName);
++
++int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name);
++int yaffs_DeleteObject(yaffs_Object *obj);
++
++int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize);
++int yaffs_GetObjectFileLength(yaffs_Object *obj);
++int yaffs_GetObjectInode(yaffs_Object *obj);
++unsigned yaffs_GetObjectType(yaffs_Object *obj);
++int yaffs_GetObjectLinkCount(yaffs_Object *obj);
++
++int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr);
++int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr);
++
++/* File operations */
++int yaffs_ReadDataFromFile(yaffs_Object *obj, __u8 *buffer, loff_t offset,
++ int nBytes);
++int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, loff_t offset,
++ int nBytes, int writeThrough);
++int yaffs_ResizeFile(yaffs_Object *obj, loff_t newSize);
++
++yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
++ __u32 mode, __u32 uid, __u32 gid);
++
++int yaffs_FlushFile(yaffs_Object *obj, int updateTime, int dataSync);
++
++/* Flushing and checkpointing */
++void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
++
++int yaffs_CheckpointSave(yaffs_Device *dev);
++int yaffs_CheckpointRestore(yaffs_Device *dev);
++
++/* Directory operations */
++yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
++ __u32 mode, __u32 uid, __u32 gid);
++yaffs_Object *yaffs_FindObjectByName(yaffs_Object *theDir, const YCHAR *name);
++int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,
++ int (*fn) (yaffs_Object *));
++
++yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number);
++
++/* Link operations */
++yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
++ yaffs_Object *equivalentObject);
++
++yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj);
++
++/* Symlink operations */
++yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
++ __u32 mode, __u32 uid, __u32 gid,
++ const YCHAR *alias);
++YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj);
++
++/* Special inodes (fifos, sockets and devices) */
++yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
++ __u32 mode, __u32 uid, __u32 gid, __u32 rdev);
++
++/* Special directories */
++yaffs_Object *yaffs_Root(yaffs_Device *dev);
++yaffs_Object *yaffs_LostNFound(yaffs_Device *dev);
++
++#ifdef CONFIG_YAFFS_WINCE
++/* CONFIG_YAFFS_WINCE special stuff */
++void yfsd_WinFileTimeNow(__u32 target[2]);
++#endif
++
++#ifdef __KERNEL__
++
++void yaffs_HandleDeferedFree(yaffs_Object *obj);
++#endif
++
++/* Debug dump */
++int yaffs_DumpObject(yaffs_Object *obj);
++
++void yaffs_GutsTest(yaffs_Device *dev);
++
++/* A few useful functions */
++void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
++void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn);
++int yaffs_CheckFF(__u8 *buffer, int nBytes);
++void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
++
++__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo);
++void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
++
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffsinterface.h linux-2.6.29-v2010041601/fs/yaffs2/yaffsinterface.h
+--- linux-2.6.29/fs/yaffs2/yaffsinterface.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffsinterface.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,21 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFSINTERFACE_H__
++#define __YAFFSINTERFACE_H__
++
++int yaffs_Initialise(unsigned nBlocks);
++
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_mtdif1.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_mtdif1.c
+--- linux-2.6.29/fs/yaffs2/yaffs_mtdif1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_mtdif1.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,362 @@
++/*
++ * YAFFS: Yet another FFS. A NAND-flash specific file system.
++ * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
++ *
++ * Copyright (C) 2002 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * This program is free software; you can 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 module provides the interface between yaffs_nand.c and the
++ * MTD API. This version is used when the MTD interface supports the
++ * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
++ * and we have small-page NAND device.
++ *
++ * These functions are invoked via function pointers in yaffs_nand.c.
++ * This replaces functionality provided by functions in yaffs_mtdif.c
++ * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
++ * called in yaffs_mtdif.c when the function pointers are NULL.
++ * We assume the MTD layer is performing ECC (useNANDECC is true).
++ */
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_guts.h"
++#include "yaffs_packedtags1.h"
++#include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */
++
++#include "linux/kernel.h"
++#include "linux/version.h"
++#include "linux/types.h"
++#include "linux/mtd/mtd.h"
++
++/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
++
++const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.12 2010-01-11 04:06:46 charles Exp $";
++
++#ifndef CONFIG_YAFFS_9BYTE_TAGS
++# define YTAG1_SIZE 8
++#else
++# define YTAG1_SIZE 9
++#endif
++
++#if 0
++/* Use the following nand_ecclayout with MTD when using
++ * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
++ * If you have existing Yaffs images and the byte order differs from this,
++ * adjust 'oobfree' to match your existing Yaffs data.
++ *
++ * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
++ * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
++ * the 9th byte.
++ *
++ * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
++ * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
++ * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
++ * byte and B is the small-page bad-block indicator byte.
++ */
++static struct nand_ecclayout nand_oob_16 = {
++ .eccbytes = 6,
++ .eccpos = { 8, 9, 10, 13, 14, 15 },
++ .oobavail = 9,
++ .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
++};
++#endif
++
++/* Write a chunk (page) of data to NAND.
++ *
++ * Caller always provides ExtendedTags data which are converted to a more
++ * compact (packed) form for storage in NAND. A mini-ECC runs over the
++ * contents of the tags meta-data; used to valid the tags when read.
++ *
++ * - Pack ExtendedTags to PackedTags1 form
++ * - Compute mini-ECC for PackedTags1
++ * - Write data and packed tags to NAND.
++ *
++ * Note: Due to the use of the PackedTags1 meta-data which does not include
++ * a full sequence number (as found in the larger PackedTags2 form) it is
++ * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
++ * discarded and dirty. This is not ideal: newer NAND parts are supposed
++ * to be written just once. When Yaffs performs this operation, this
++ * function is called with a NULL data pointer -- calling MTD write_oob
++ * without data is valid usage (2.6.17).
++ *
++ * Any underlying MTD error results in YAFFS_FAIL.
++ * Returns YAFFS_OK or YAFFS_FAIL.
++ */
++int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
++ int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
++{
++ struct mtd_info *mtd = dev->genericDevice;
++ int chunkBytes = dev->nDataBytesPerChunk;
++ loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
++ struct mtd_oob_ops ops;
++ yaffs_PackedTags1 pt1;
++ int retval;
++
++ /* we assume that PackedTags1 and yaffs_Tags are compatible */
++ compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
++ compile_time_assertion(sizeof(yaffs_Tags) == 8);
++
++ yaffs_PackTags1(&pt1, etags);
++ yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
++
++ /* When deleting a chunk, the upper layer provides only skeletal
++ * etags, one with chunkDeleted set. However, we need to update the
++ * tags, not erase them completely. So we use the NAND write property
++ * that only zeroed-bits stick and set tag bytes to all-ones and
++ * zero just the (not) deleted bit.
++ */
++#ifndef CONFIG_YAFFS_9BYTE_TAGS
++ if (etags->chunkDeleted) {
++ memset(&pt1, 0xff, 8);
++ /* clear delete status bit to indicate deleted */
++ pt1.deleted = 0;
++ }
++#else
++ ((__u8 *)&pt1)[8] = 0xff;
++ if (etags->chunkDeleted) {
++ memset(&pt1, 0xff, 8);
++ /* zero pageStatus byte to indicate deleted */
++ ((__u8 *)&pt1)[8] = 0;
++ }
++#endif
++
++ memset(&ops, 0, sizeof(ops));
++ ops.mode = MTD_OOB_AUTO;
++ ops.len = (data) ? chunkBytes : 0;
++ ops.ooblen = YTAG1_SIZE;
++ ops.datbuf = (__u8 *)data;
++ ops.oobbuf = (__u8 *)&pt1;
++
++ retval = mtd->write_oob(mtd, addr, &ops);
++ if (retval) {
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "write_oob failed, chunk %d, mtd error %d\n",
++ chunkInNAND, retval);
++ }
++ return retval ? YAFFS_FAIL : YAFFS_OK;
++}
++
++/* Return with empty ExtendedTags but add eccResult.
++ */
++static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval)
++{
++ if (etags) {
++ memset(etags, 0, sizeof(*etags));
++ etags->eccResult = eccResult;
++ }
++ return retval;
++}
++
++/* Read a chunk (page) from NAND.
++ *
++ * Caller expects ExtendedTags data to be usable even on error; that is,
++ * all members except eccResult and blockBad are zeroed.
++ *
++ * - Check ECC results for data (if applicable)
++ * - Check for blank/erased block (return empty ExtendedTags if blank)
++ * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
++ * - Convert PackedTags1 to ExtendedTags
++ * - Update eccResult and blockBad members to refect state.
++ *
++ * Returns YAFFS_OK or YAFFS_FAIL.
++ */
++int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
++ int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)
++{
++ struct mtd_info *mtd = dev->genericDevice;
++ int chunkBytes = dev->nDataBytesPerChunk;
++ loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
++ int eccres = YAFFS_ECC_RESULT_NO_ERROR;
++ struct mtd_oob_ops ops;
++ yaffs_PackedTags1 pt1;
++ int retval;
++ int deleted;
++
++ memset(&ops, 0, sizeof(ops));
++ ops.mode = MTD_OOB_AUTO;
++ ops.len = (data) ? chunkBytes : 0;
++ ops.ooblen = YTAG1_SIZE;
++ ops.datbuf = data;
++ ops.oobbuf = (__u8 *)&pt1;
++
++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
++ /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
++ * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
++ */
++ ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
++#endif
++ /* Read page and oob using MTD.
++ * Check status and determine ECC result.
++ */
++ retval = mtd->read_oob(mtd, addr, &ops);
++ if (retval) {
++ yaffs_trace(YAFFS_TRACE_MTD,
++ "read_oob failed, chunk %d, mtd error %d\n",
++ chunkInNAND, retval);
++ }
++
++ switch (retval) {
++ case 0:
++ /* no error */
++ break;
++
++ case -EUCLEAN:
++ /* MTD's ECC fixed the data */
++ eccres = YAFFS_ECC_RESULT_FIXED;
++ dev->eccFixed++;
++ break;
++
++ case -EBADMSG:
++ /* MTD's ECC could not fix the data */
++ dev->eccUnfixed++;
++ /* fall into... */
++ default:
++ rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
++ etags->blockBad = (mtd->block_isbad)(mtd, addr);
++ return YAFFS_FAIL;
++ }
++
++ /* Check for a blank/erased chunk.
++ */
++ if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
++ /* when blank, upper layers want eccResult to be <= NO_ERROR */
++ return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
++ }
++
++#ifndef CONFIG_YAFFS_9BYTE_TAGS
++ /* Read deleted status (bit) then return it to it's non-deleted
++ * state before performing tags mini-ECC check. pt1.deleted is
++ * inverted.
++ */
++ deleted = !pt1.deleted;
++ pt1.deleted = 1;
++#else
++ deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
++#endif
++
++ /* Check the packed tags mini-ECC and correct if necessary/possible.
++ */
++ retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
++ switch (retval) {
++ case 0:
++ /* no tags error, use MTD result */
++ break;
++ case 1:
++ /* recovered tags-ECC error */
++ dev->tagsEccFixed++;
++ if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
++ eccres = YAFFS_ECC_RESULT_FIXED;
++ break;
++ default:
++ /* unrecovered tags-ECC error */
++ dev->tagsEccUnfixed++;
++ return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
++ }
++
++ /* Unpack the tags to extended form and set ECC result.
++ * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
++ */
++ pt1.shouldBeFF = 0xFFFFFFFF;
++ yaffs_UnpackTags1(etags, &pt1);
++ etags->eccResult = eccres;
++
++ /* Set deleted state */
++ etags->chunkDeleted = deleted;
++ return YAFFS_OK;
++}
++
++/* Mark a block bad.
++ *
++ * This is a persistant state.
++ * Use of this function should be rare.
++ *
++ * Returns YAFFS_OK or YAFFS_FAIL.
++ */
++int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
++{
++ struct mtd_info *mtd = dev->genericDevice;
++ int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
++ int retval;
++
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
++
++ retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
++ return (retval) ? YAFFS_FAIL : YAFFS_OK;
++}
++
++/* Check any MTD prerequists.
++ *
++ * Returns YAFFS_OK or YAFFS_FAIL.
++ */
++static int nandmtd1_TestPrerequists(struct mtd_info *mtd)
++{
++ /* 2.6.18 has mtd->ecclayout->oobavail */
++ /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
++ int oobavail = mtd->ecclayout->oobavail;
++
++ if (oobavail < YTAG1_SIZE) {
++ yaffs_trace(YAFFS_TRACE_ERROR,
++ "mtd device has only %d bytes for tags, need %d\n",
++ oobavail, YTAG1_SIZE);
++ return YAFFS_FAIL;
++ }
++ return YAFFS_OK;
++}
++
++/* Query for the current state of a specific block.
++ *
++ * Examine the tags of the first chunk of the block and return the state:
++ * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
++ * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
++ * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
++ *
++ * Always returns YAFFS_OK.
++ */
++int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
++ yaffs_BlockState *pState, __u32 *pSequenceNumber)
++{
++ struct mtd_info *mtd = dev->genericDevice;
++ int chunkNo = blockNo * dev->nChunksPerBlock;
++ loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
++ yaffs_ExtendedTags etags;
++ int state = YAFFS_BLOCK_STATE_DEAD;
++ int seqnum = 0;
++ int retval;
++
++ /* We don't yet have a good place to test for MTD config prerequists.
++ * Do it here as we are called during the initial scan.
++ */
++ if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK)
++ return YAFFS_FAIL;
++
++ retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
++ etags.blockBad = (mtd->block_isbad)(mtd, addr);
++ if (etags.blockBad) {
++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
++ "block %d is marked bad\n", blockNo);
++ state = YAFFS_BLOCK_STATE_DEAD;
++ } else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
++ /* bad tags, need to look more closely */
++ state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
++ } else if (etags.chunkUsed) {
++ state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
++ seqnum = etags.sequenceNumber;
++ } else {
++ state = YAFFS_BLOCK_STATE_EMPTY;
++ }
++
++ *pState = state;
++ *pSequenceNumber = seqnum;
++
++ /* query always succeeds */
++ return YAFFS_OK;
++}
++
++#endif /*MTD_VERSION*/
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_mtdif1.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_mtdif1.h
+--- linux-2.6.29/fs/yaffs2/yaffs_mtdif1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_mtdif1.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_MTDIF1_H__
++#define __YAFFS_MTDIF1_H__
++
++int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
++ const __u8 *data, const yaffs_ExtendedTags *tags);
++
++int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
++ __u8 *data, yaffs_ExtendedTags *tags);
++
++int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
++
++int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
++ yaffs_BlockState *state, __u32 *sequenceNumber);
++
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_mtdif2.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_mtdif2.c
+--- linux-2.6.29/fs/yaffs2/yaffs_mtdif2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_mtdif2.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,252 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* mtd interface for YAFFS2 */
++
++const char *yaffs_mtdif2_c_version =
++ "$Id: yaffs_mtdif2.c,v 1.26 2010-01-11 21:43:18 charles Exp $";
++
++#include "yportenv.h"
++#include "yaffs_trace.h"
++
++#include "yaffs_mtdif2.h"
++
++#include "linux/mtd/mtd.h"
++#include "linux/types.h"
++#include "linux/time.h"
++
++#include "yaffs_packedtags2.h"
++
++/* NB For use with inband tags....
++ * We assume that the data buffer is of size totalBytersPerChunk so that we can also
++ * use it to load the tags.
++ */
++int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
++ const __u8 *data,
++ const yaffs_ExtendedTags *tags)
++{
++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
++ struct mtd_oob_ops ops;
++#else
++ size_t dummy;
++#endif
++ int retval = 0;
++
++ loff_t addr;
++
++ yaffs_PackedTags2 pt;
++
++ int packed_tags_size = dev->noTagsECC ? sizeof(pt.t) : sizeof(pt);
++ void * packed_tags_ptr = dev->noTagsECC ? (void *) &pt.t : (void *)&pt;
++
++ T(YAFFS_TRACE_MTD,
++ (TSTR
++ ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
++ TENDSTR), chunkInNAND, data, tags));
++
++
++ addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
++
++ /* For yaffs2 writing there must be both data and tags.
++ * If we're using inband tags, then the tags are stuffed into
++ * the end of the data buffer.
++ */
++ if (!data || !tags)
++ BUG();
++ else if (dev->inbandTags) {
++ yaffs_PackedTags2TagsPart *pt2tp;
++ pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
++ yaffs_PackTags2TagsPart(pt2tp, tags);
++ } else
++ yaffs_PackTags2(&pt, tags, !dev->noTagsECC);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ ops.mode = MTD_OOB_AUTO;
++ ops.ooblen = (dev->inbandTags) ? 0 : packed_tags_size;
++ ops.len = dev->totalBytesPerChunk;
++ ops.ooboffs = 0;
++ ops.datbuf = (__u8 *)data;
++ ops.oobbuf = (dev->inbandTags) ? NULL : packed_tags_ptr;
++ retval = mtd->write_oob(mtd, addr, &ops);
++
++#else
++ if (!dev->inbandTags) {
++ retval =
++ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
++ &dummy, data, (__u8 *) packed_tags_ptr, NULL);
++ } else {
++ retval =
++ mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
++ data);
++ }
++#endif
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
++ __u8 *data, yaffs_ExtendedTags *tags)
++{
++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
++ struct mtd_oob_ops ops;
++#endif
++ size_t dummy;
++ int retval = 0;
++ int localData = 0;
++
++ loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
++
++ yaffs_PackedTags2 pt;
++
++ int packed_tags_size = dev->noTagsECC ? sizeof(pt.t) : sizeof(pt);
++ void * packed_tags_ptr = dev->noTagsECC ? (void *) &pt.t: (void *)&pt;
++
++ T(YAFFS_TRACE_MTD,
++ (TSTR
++ ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
++ TENDSTR), chunkInNAND, data, tags));
++
++ if (dev->inbandTags) {
++
++ if (!data) {
++ localData = 1;
++ data = yaffs_GetTempBuffer(dev, __LINE__);
++ }
++
++
++ }
++
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
++ if (dev->inbandTags || (data && !tags))
++ retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
++ &dummy, data);
++ else if (tags) {
++ ops.mode = MTD_OOB_AUTO;
++ ops.ooblen = packed_tags_size;
++ ops.len = data ? dev->nDataBytesPerChunk : packed_tags_size;
++ ops.ooboffs = 0;
++ ops.datbuf = data;
++ ops.oobbuf = dev->spareBuffer;
++ retval = mtd->read_oob(mtd, addr, &ops);
++ }
++#else
++ if (!dev->inbandTags && data && tags) {
++
++ retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
++ &dummy, data, dev->spareBuffer,
++ NULL);
++ } else {
++ if (data)
++ retval =
++ mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
++ data);
++ if (!dev->inbandTags && tags)
++ retval =
++ mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
++ dev->spareBuffer);
++ }
++#endif
++
++
++ if (dev->inbandTags) {
++ if (tags) {
++ yaffs_PackedTags2TagsPart *pt2tp;
++ pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
++ yaffs_UnpackTags2TagsPart(tags, pt2tp);
++ }
++ } else {
++ if (tags) {
++ memcpy(packed_tags_ptr, dev->spareBuffer, packed_tags_size);
++ yaffs_UnpackTags2(tags, &pt, !dev->noTagsECC);
++ }
++ }
++
++ if (localData)
++ yaffs_ReleaseTempBuffer(dev, data, __LINE__);
++
++ if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
++ tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
++{
++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
++ int retval;
++ T(YAFFS_TRACE_MTD,
++ (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
++
++ retval =
++ mtd->block_markbad(mtd,
++ blockNo * dev->nChunksPerBlock *
++ dev->totalBytesPerChunk);
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++
++}
++
++int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
++ yaffs_BlockState *state, __u32 *sequenceNumber)
++{
++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
++ int retval;
++
++ T(YAFFS_TRACE_MTD,
++ (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
++ retval =
++ mtd->block_isbad(mtd,
++ blockNo * dev->nChunksPerBlock *
++ dev->totalBytesPerChunk);
++
++ if (retval) {
++ T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
++
++ *state = YAFFS_BLOCK_STATE_DEAD;
++ *sequenceNumber = 0;
++ } else {
++ yaffs_ExtendedTags t;
++ nandmtd2_ReadChunkWithTagsFromNAND(dev,
++ blockNo *
++ dev->nChunksPerBlock, NULL,
++ &t);
++
++ if (t.chunkUsed) {
++ *sequenceNumber = t.sequenceNumber;
++ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
++ } else {
++ *sequenceNumber = 0;
++ *state = YAFFS_BLOCK_STATE_EMPTY;
++ }
++ }
++ T(YAFFS_TRACE_MTD,
++ (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
++ *state));
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_mtdif2.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_mtdif2.h
+--- linux-2.6.29/fs/yaffs2/yaffs_mtdif2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_mtdif2.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,29 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_MTDIF2_H__
++#define __YAFFS_MTDIF2_H__
++
++#include "yaffs_guts.h"
++int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
++ const __u8 *data,
++ const yaffs_ExtendedTags *tags);
++int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
++ __u8 *data, yaffs_ExtendedTags *tags);
++int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
++int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
++ yaffs_BlockState *state, __u32 *sequenceNumber);
++
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_mtdif.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_mtdif.c
+--- linux-2.6.29/fs/yaffs2/yaffs_mtdif.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_mtdif.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,241 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++const char *yaffs_mtdif_c_version =
++ "$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $";
++
++#include "yportenv.h"
++
++
++#include "yaffs_mtdif.h"
++
++#include "linux/mtd/mtd.h"
++#include "linux/types.h"
++#include "linux/time.h"
++#include "linux/mtd/nand.h"
++
++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
++static struct nand_oobinfo yaffs_oobinfo = {
++ .useecc = 1,
++ .eccbytes = 6,
++ .eccpos = {8, 9, 10, 13, 14, 15}
++};
++
++static struct nand_oobinfo yaffs_noeccinfo = {
++ .useecc = 0,
++};
++#endif
++
++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
++static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
++{
++ oob[0] = spare->tagByte0;
++ oob[1] = spare->tagByte1;
++ oob[2] = spare->tagByte2;
++ oob[3] = spare->tagByte3;
++ oob[4] = spare->tagByte4;
++ oob[5] = spare->tagByte5 & 0x3f;
++ oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80;
++ oob[5] |= spare->pageStatus == 0 ? 0 : 0x40;
++ oob[6] = spare->tagByte6;
++ oob[7] = spare->tagByte7;
++}
++
++static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
++{
++ struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
++ spare->tagByte0 = oob[0];
++ spare->tagByte1 = oob[1];
++ spare->tagByte2 = oob[2];
++ spare->tagByte3 = oob[3];
++ spare->tagByte4 = oob[4];
++ spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
++ spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
++ spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
++ spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
++ spare->tagByte6 = oob[6];
++ spare->tagByte7 = oob[7];
++ spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
++
++ nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
++}
++#endif
++
++int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
++ const __u8 *data, const yaffs_Spare *spare)
++{
++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
++ struct mtd_oob_ops ops;
++#endif
++ size_t dummy;
++ int retval = 0;
++
++ loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
++ __u8 spareAsBytes[8]; /* OOB */
++
++ if (data && !spare)
++ retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
++ &dummy, data);
++ else if (spare) {
++ if (dev->useNANDECC) {
++ translate_spare2oob(spare, spareAsBytes);
++ ops.mode = MTD_OOB_AUTO;
++ ops.ooblen = 8; /* temp hack */
++ } else {
++ ops.mode = MTD_OOB_RAW;
++ ops.ooblen = YAFFS_BYTES_PER_SPARE;
++ }
++ ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
++ ops.datbuf = (u8 *)data;
++ ops.ooboffs = 0;
++ ops.oobbuf = spareAsBytes;
++ retval = mtd->write_oob(mtd, addr, &ops);
++ }
++#else
++ __u8 *spareAsBytes = (__u8 *) spare;
++
++ if (data && spare) {
++ if (dev->useNANDECC)
++ retval =
++ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
++ &dummy, data, spareAsBytes,
++ &yaffs_oobinfo);
++ else
++ retval =
++ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
++ &dummy, data, spareAsBytes,
++ &yaffs_noeccinfo);
++ } else {
++ if (data)
++ retval =
++ mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
++ data);
++ if (spare)
++ retval =
++ mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
++ &dummy, spareAsBytes);
++ }
++#endif
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
++ yaffs_Spare *spare)
++{
++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
++ struct mtd_oob_ops ops;
++#endif
++ size_t dummy;
++ int retval = 0;
++
++ loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
++ __u8 spareAsBytes[8]; /* OOB */
++
++ if (data && !spare)
++ retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
++ &dummy, data);
++ else if (spare) {
++ if (dev->useNANDECC) {
++ ops.mode = MTD_OOB_AUTO;
++ ops.ooblen = 8; /* temp hack */
++ } else {
++ ops.mode = MTD_OOB_RAW;
++ ops.ooblen = YAFFS_BYTES_PER_SPARE;
++ }
++ ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
++ ops.datbuf = data;
++ ops.ooboffs = 0;
++ ops.oobbuf = spareAsBytes;
++ retval = mtd->read_oob(mtd, addr, &ops);
++ if (dev->useNANDECC)
++ translate_oob2spare(spare, spareAsBytes);
++ }
++#else
++ __u8 *spareAsBytes = (__u8 *) spare;
++
++ if (data && spare) {
++ if (dev->useNANDECC) {
++ /* Careful, this call adds 2 ints */
++ /* to the end of the spare data. Calling function */
++ /* should allocate enough memory for spare, */
++ /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
++ retval =
++ mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
++ &dummy, data, spareAsBytes,
++ &yaffs_oobinfo);
++ } else {
++ retval =
++ mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
++ &dummy, data, spareAsBytes,
++ &yaffs_noeccinfo);
++ }
++ } else {
++ if (data)
++ retval =
++ mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
++ data);
++ if (spare)
++ retval =
++ mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
++ &dummy, spareAsBytes);
++ }
++#endif
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
++{
++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
++ __u32 addr =
++ ((loff_t) blockNumber) * dev->nDataBytesPerChunk
++ * dev->nChunksPerBlock;
++ struct erase_info ei;
++ int retval = 0;
++
++ ei.mtd = mtd;
++ ei.addr = addr;
++ ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
++ ei.time = 1000;
++ ei.retries = 2;
++ ei.callback = NULL;
++ ei.priv = (u_long) dev;
++
++ /* Todo finish off the ei if required */
++
++ sema_init(&dev->sem, 0);
++
++ retval = mtd->erase(mtd, &ei);
++
++ if (retval == 0)
++ return YAFFS_OK;
++ else
++ return YAFFS_FAIL;
++}
++
++int nandmtd_InitialiseNAND(yaffs_Device *dev)
++{
++ return YAFFS_OK;
++}
++
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_mtdif.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_mtdif.h
+--- linux-2.6.29/fs/yaffs2/yaffs_mtdif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_mtdif.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,32 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_MTDIF_H__
++#define __YAFFS_MTDIF_H__
++
++#include "yaffs_guts.h"
++
++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
++extern struct nand_oobinfo yaffs_oobinfo;
++extern struct nand_oobinfo yaffs_noeccinfo;
++#endif
++
++int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
++ const __u8 *data, const yaffs_Spare *spare);
++int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
++ yaffs_Spare *spare);
++int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
++int nandmtd_InitialiseNAND(yaffs_Device *dev);
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_nand.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_nand.c
+--- linux-2.6.29/fs/yaffs2/yaffs_nand.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_nand.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,140 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++const char *yaffs_nand_c_version =
++ "$Id: yaffs_nand.c,v 1.11 2009-09-09 03:03:01 charles Exp $";
++
++#include "yaffs_nand.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_tagsvalidity.h"
++
++#include "yaffs_getblockinfo.h"
++
++int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
++ __u8 *buffer,
++ yaffs_ExtendedTags *tags)
++{
++ int result;
++ yaffs_ExtendedTags localTags;
++
++ int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
++
++ dev->nPageReads++;
++
++ /* If there are no tags provided, use local tags to get prioritised gc working */
++ if (!tags)
++ tags = &localTags;
++
++ if (dev->readChunkWithTagsFromNAND)
++ result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
++ tags);
++ else
++ result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
++ realignedChunkInNAND,
++ buffer,
++ tags);
++ if (tags &&
++ tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) {
++
++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
++ yaffs_HandleChunkError(dev, bi);
++ }
++
++ return result;
++}
++
++int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
++ int chunkInNAND,
++ const __u8 *buffer,
++ yaffs_ExtendedTags *tags)
++{
++
++ dev->nPageWrites++;
++
++ chunkInNAND -= dev->chunkOffset;
++
++
++ if (tags) {
++ tags->sequenceNumber = dev->sequenceNumber;
++ tags->chunkUsed = 1;
++ if (!yaffs_ValidateTags(tags)) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("Writing uninitialised tags" TENDSTR)));
++ YBUG();
++ }
++ T(YAFFS_TRACE_WRITE,
++ (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
++ tags->objectId, tags->chunkId));
++ } else {
++ T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
++ YBUG();
++ }
++
++ if (dev->writeChunkWithTagsToNAND)
++ return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
++ tags);
++ else
++ return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
++ chunkInNAND,
++ buffer,
++ tags);
++}
++
++int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
++{
++ blockNo -= dev->blockOffset;
++
++
++ if (dev->markNANDBlockBad)
++ return dev->markNANDBlockBad(dev, blockNo);
++ else
++ return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
++}
++
++int yaffs_QueryInitialBlockState(yaffs_Device *dev,
++ int blockNo,
++ yaffs_BlockState *state,
++ __u32 *sequenceNumber)
++{
++ blockNo -= dev->blockOffset;
++
++ if (dev->queryNANDBlock)
++ return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
++ else
++ return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
++ state,
++ sequenceNumber);
++}
++
++
++int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
++ int blockInNAND)
++{
++ int result;
++
++ blockInNAND -= dev->blockOffset;
++
++ dev->nBlockErasures++;
++
++ result = dev->eraseBlockInNAND(dev, blockInNAND);
++
++ return result;
++}
++
++int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
++{
++ return dev->initialiseNAND(dev);
++}
++
++
++
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_nandemul2k.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_nandemul2k.h
+--- linux-2.6.29/fs/yaffs2/yaffs_nandemul2k.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_nandemul2k.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* Interface to emulated NAND functions (2k page size) */
++
++#ifndef __YAFFS_NANDEMUL2K_H__
++#define __YAFFS_NANDEMUL2K_H__
++
++#include "yaffs_guts.h"
++
++int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
++ int chunkInNAND, const __u8 *data,
++ const yaffs_ExtendedTags *tags);
++int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
++ int chunkInNAND, __u8 *data,
++ yaffs_ExtendedTags *tags);
++int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
++int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
++ yaffs_BlockState *state, __u32 *sequenceNumber);
++int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
++ int blockInNAND);
++int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
++int nandemul2k_GetBytesPerChunk(void);
++int nandemul2k_GetChunksPerBlock(void);
++int nandemul2k_GetNumberOfBlocks(void);
++
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_nand.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_nand.h
+--- linux-2.6.29/fs/yaffs2/yaffs_nand.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_nand.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_NAND_H__
++#define __YAFFS_NAND_H__
++#include "yaffs_guts.h"
++
++
++
++int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
++ __u8 *buffer,
++ yaffs_ExtendedTags *tags);
++
++int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
++ int chunkInNAND,
++ const __u8 *buffer,
++ yaffs_ExtendedTags *tags);
++
++int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo);
++
++int yaffs_QueryInitialBlockState(yaffs_Device *dev,
++ int blockNo,
++ yaffs_BlockState *state,
++ unsigned *sequenceNumber);
++
++int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
++ int blockInNAND);
++
++int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
++
++#endif
++
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_packedtags1.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_packedtags1.c
+--- linux-2.6.29/fs/yaffs2/yaffs_packedtags1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_packedtags1.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,50 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can 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 "yaffs_packedtags1.h"
++#include "yportenv.h"
++
++void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t)
++{
++ pt->chunkId = t->chunkId;
++ pt->serialNumber = t->serialNumber;
++ pt->byteCount = t->byteCount;
++ pt->objectId = t->objectId;
++ pt->ecc = 0;
++ pt->deleted = (t->chunkDeleted) ? 0 : 1;
++ pt->unusedStuff = 0;
++ pt->shouldBeFF = 0xFFFFFFFF;
++
++}
++
++void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt)
++{
++ static const __u8 allFF[] =
++ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++0xff };
++
++ if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
++ t->blockBad = 0;
++ if (pt->shouldBeFF != 0xFFFFFFFF)
++ t->blockBad = 1;
++ t->chunkUsed = 1;
++ t->objectId = pt->objectId;
++ t->chunkId = pt->chunkId;
++ t->byteCount = pt->byteCount;
++ t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
++ t->chunkDeleted = (pt->deleted) ? 0 : 1;
++ t->serialNumber = pt->serialNumber;
++ } else {
++ memset(t, 0, sizeof(yaffs_ExtendedTags));
++ }
++}
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_packedtags1.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_packedtags1.h
+--- linux-2.6.29/fs/yaffs2/yaffs_packedtags1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_packedtags1.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,37 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
++
++#ifndef __YAFFS_PACKEDTAGS1_H__
++#define __YAFFS_PACKEDTAGS1_H__
++
++#include "yaffs_guts.h"
++
++typedef struct {
++ unsigned chunkId:20;
++ unsigned serialNumber:2;
++ unsigned byteCount:10;
++ unsigned objectId:18;
++ unsigned ecc:12;
++ unsigned deleted:1;
++ unsigned unusedStuff:1;
++ unsigned shouldBeFF;
++
++} yaffs_PackedTags1;
++
++void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t);
++void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt);
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_packedtags2.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_packedtags2.c
+--- linux-2.6.29/fs/yaffs2/yaffs_packedtags2.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_packedtags2.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,198 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can 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 "yaffs_packedtags2.h"
++#include "yportenv.h"
++#include "yaffs_trace.h"
++#include "yaffs_tagsvalidity.h"
++
++/* This code packs a set of extended tags into a binary structure for
++ * NAND storage
++ */
++
++/* Some of the information is "extra" struff which can be packed in to
++ * speed scanning
++ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
++ */
++
++/* Extra flags applied to chunkId */
++
++#define EXTRA_HEADER_INFO_FLAG 0x80000000
++#define EXTRA_SHRINK_FLAG 0x40000000
++#define EXTRA_SHADOWS_FLAG 0x20000000
++#define EXTRA_SPARE_FLAGS 0x10000000
++
++#define ALL_EXTRA_FLAGS 0xF0000000
++
++/* Also, the top 4 bits of the object Id are set to the object type. */
++#define EXTRA_OBJECT_TYPE_SHIFT (28)
++#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
++
++
++static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt)
++{
++ T(YAFFS_TRACE_MTD,
++ (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
++ ptt->objectId, ptt->chunkId, ptt->byteCount,
++ ptt->sequenceNumber));
++}
++static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
++{
++ yaffs_DumpPackedTags2TagsPart(&pt->t);
++}
++
++static void yaffs_DumpTags2(const yaffs_ExtendedTags *t)
++{
++ T(YAFFS_TRACE_MTD,
++ (TSTR
++ ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
++ TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
++ t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
++ t->sequenceNumber));
++
++}
++
++void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt,
++ const yaffs_ExtendedTags *t)
++{
++ ptt->chunkId = t->chunkId;
++ ptt->sequenceNumber = t->sequenceNumber;
++ ptt->byteCount = t->byteCount;
++ ptt->objectId = t->objectId;
++
++ if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
++ /* Store the extra header info instead */
++ /* We save the parent object in the chunkId */
++ ptt->chunkId = EXTRA_HEADER_INFO_FLAG
++ | t->extraParentObjectId;
++ if (t->extraIsShrinkHeader)
++ ptt->chunkId |= EXTRA_SHRINK_FLAG;
++ if (t->extraShadows)
++ ptt->chunkId |= EXTRA_SHADOWS_FLAG;
++
++ ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
++ ptt->objectId |=
++ (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
++
++ if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
++ ptt->byteCount = t->extraEquivalentObjectId;
++ else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE)
++ ptt->byteCount = t->extraFileLength;
++ else
++ ptt->byteCount = 0;
++ }
++
++ yaffs_DumpPackedTags2TagsPart(ptt);
++ yaffs_DumpTags2(t);
++}
++
++
++void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC)
++{
++ yaffs_PackTags2TagsPart(&pt->t, t);
++
++ if(tagsECC)
++ yaffs_ECCCalculateOther((unsigned char *)&pt->t,
++ sizeof(yaffs_PackedTags2TagsPart),
++ &pt->ecc);
++}
++
++
++void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t,
++ yaffs_PackedTags2TagsPart *ptt)
++{
++
++ memset(t, 0, sizeof(yaffs_ExtendedTags));
++
++ yaffs_InitialiseTags(t);
++
++ if (ptt->sequenceNumber != 0xFFFFFFFF) {
++ t->blockBad = 0;
++ t->chunkUsed = 1;
++ t->objectId = ptt->objectId;
++ t->chunkId = ptt->chunkId;
++ t->byteCount = ptt->byteCount;
++ t->chunkDeleted = 0;
++ t->serialNumber = 0;
++ t->sequenceNumber = ptt->sequenceNumber;
++
++ /* Do extra header info stuff */
++
++ if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) {
++ t->chunkId = 0;
++ t->byteCount = 0;
++
++ t->extraHeaderInfoAvailable = 1;
++ t->extraParentObjectId =
++ ptt->chunkId & (~(ALL_EXTRA_FLAGS));
++ t->extraIsShrinkHeader =
++ (ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
++ t->extraShadows =
++ (ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
++ t->extraObjectType =
++ ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT;
++ t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
++
++ if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
++ t->extraEquivalentObjectId = ptt->byteCount;
++ else
++ t->extraFileLength = ptt->byteCount;
++ }
++ }
++
++ yaffs_DumpPackedTags2TagsPart(ptt);
++ yaffs_DumpTags2(t);
++
++}
++
++
++void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC)
++{
++
++ yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR;
++
++ if (pt->t.sequenceNumber != 0xFFFFFFFF &&
++ tagsECC){
++ /* Chunk is in use and we need to do ECC */
++
++ yaffs_ECCOther ecc;
++ int result;
++ yaffs_ECCCalculateOther((unsigned char *)&pt->t,
++ sizeof(yaffs_PackedTags2TagsPart),
++ &ecc);
++ result = yaffs_ECCCorrectOther((unsigned char *)&pt->t,
++ sizeof(yaffs_PackedTags2TagsPart),
++ &pt->ecc, &ecc);
++ switch (result) {
++ case 0:
++ eccResult = YAFFS_ECC_RESULT_NO_ERROR;
++ break;
++ case 1:
++ eccResult = YAFFS_ECC_RESULT_FIXED;
++ break;
++ case -1:
++ eccResult = YAFFS_ECC_RESULT_UNFIXED;
++ break;
++ default:
++ eccResult = YAFFS_ECC_RESULT_UNKNOWN;
++ }
++ }
++
++ yaffs_UnpackTags2TagsPart(t, &pt->t);
++
++ t->eccResult = eccResult;
++
++ yaffs_DumpPackedTags2(pt);
++ yaffs_DumpTags2(t);
++}
++
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_packedtags2.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_packedtags2.h
+--- linux-2.6.29/fs/yaffs2/yaffs_packedtags2.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_packedtags2.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,43 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
++
++#ifndef __YAFFS_PACKEDTAGS2_H__
++#define __YAFFS_PACKEDTAGS2_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_ecc.h"
++
++typedef struct {
++ unsigned sequenceNumber;
++ unsigned objectId;
++ unsigned chunkId;
++ unsigned byteCount;
++} yaffs_PackedTags2TagsPart;
++
++typedef struct {
++ yaffs_PackedTags2TagsPart t;
++ yaffs_ECCOther ecc;
++} yaffs_PackedTags2;
++
++/* Full packed tags with ECC, used for oob tags */
++void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC);
++void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC);
++
++/* Only the tags part (no ECC for use with inband tags */
++void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t);
++void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, yaffs_PackedTags2TagsPart *pt);
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_qsort.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_qsort.c
+--- linux-2.6.29/fs/yaffs2/yaffs_qsort.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_qsort.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,163 @@
++/*
++ * Copyright (c) 1992, 1993
++ * The Regents of the University of California. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. Neither the name of the University nor the names of its contributors
++ * may be used to endorse or promote products derived from this software
++ * without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++#include "yportenv.h"
++/* #include <linux/string.h> */
++
++/*
++ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
++ */
++#define swapcode(TYPE, parmi, parmj, n) do { \
++ long i = (n) / sizeof (TYPE); \
++ register TYPE *pi = (TYPE *) (parmi); \
++ register TYPE *pj = (TYPE *) (parmj); \
++ do { \
++ register TYPE t = *pi; \
++ *pi++ = *pj; \
++ *pj++ = t; \
++ } while (--i > 0); \
++} while (0)
++
++#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
++ es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1;
++
++static __inline void
++swapfunc(char *a, char *b, int n, int swaptype)
++{
++ if (swaptype <= 1)
++ swapcode(long, a, b, n);
++ else
++ swapcode(char, a, b, n);
++}
++
++#define yswap(a, b) do { \
++ if (swaptype == 0) { \
++ long t = *(long *)(a); \
++ *(long *)(a) = *(long *)(b); \
++ *(long *)(b) = t; \
++ } else \
++ swapfunc(a, b, es, swaptype); \
++} while (0)
++
++#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
++
++static __inline char *
++med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
++{
++ return cmp(a, b) < 0 ?
++ (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a))
++ : (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c));
++}
++
++#ifndef min
++#define min(a, b) (((a) < (b)) ? (a) : (b))
++#endif
++
++void
++yaffs_qsort(void *aa, size_t n, size_t es,
++ int (*cmp)(const void *, const void *))
++{
++ char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
++ int d, r, swaptype, swap_cnt;
++ register char *a = aa;
++
++loop: SWAPINIT(a, es);
++ swap_cnt = 0;
++ if (n < 7) {
++ for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
++ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
++ pl -= es)
++ yswap(pl, pl - es);
++ return;
++ }
++ pm = (char *)a + (n / 2) * es;
++ if (n > 7) {
++ pl = (char *)a;
++ pn = (char *)a + (n - 1) * es;
++ if (n > 40) {
++ d = (n / 8) * es;
++ pl = med3(pl, pl + d, pl + 2 * d, cmp);
++ pm = med3(pm - d, pm, pm + d, cmp);
++ pn = med3(pn - 2 * d, pn - d, pn, cmp);
++ }
++ pm = med3(pl, pm, pn, cmp);
++ }
++ yswap(a, pm);
++ pa = pb = (char *)a + es;
++
++ pc = pd = (char *)a + (n - 1) * es;
++ for (;;) {
++ while (pb <= pc && (r = cmp(pb, a)) <= 0) {
++ if (r == 0) {
++ swap_cnt = 1;
++ yswap(pa, pb);
++ pa += es;
++ }
++ pb += es;
++ }
++ while (pb <= pc && (r = cmp(pc, a)) >= 0) {
++ if (r == 0) {
++ swap_cnt = 1;
++ yswap(pc, pd);
++ pd -= es;
++ }
++ pc -= es;
++ }
++ if (pb > pc)
++ break;
++ yswap(pb, pc);
++ swap_cnt = 1;
++ pb += es;
++ pc -= es;
++ }
++ if (swap_cnt == 0) { /* Switch to insertion sort */
++ for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
++ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
++ pl -= es)
++ yswap(pl, pl - es);
++ return;
++ }
++
++ pn = (char *)a + n * es;
++ r = min(pa - (char *)a, pb - pa);
++ vecswap(a, pb - r, r);
++ r = min((long)(pd - pc), (long)(pn - pd - es));
++ vecswap(pb, pn - r, r);
++ r = pb - pa;
++ if (r > es)
++ yaffs_qsort(a, r / es, es, cmp);
++ r = pd - pc;
++ if (r > es) {
++ /* Iterate rather than recurse to save stack space */
++ a = pn - r;
++ n = r / es;
++ goto loop;
++ }
++/* yaffs_qsort(pn - r, r / es, es, cmp);*/
++}
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_qsort.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_qsort.h
+--- linux-2.6.29/fs/yaffs2/yaffs_qsort.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_qsort.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,23 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++
++#ifndef __YAFFS_QSORT_H__
++#define __YAFFS_QSORT_H__
++
++extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
++ int (*cmp)(const void *, const void *));
++
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_tagscompat.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_tagscompat.c
+--- linux-2.6.29/fs/yaffs2/yaffs_tagscompat.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_tagscompat.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,539 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can 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 "yaffs_guts.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_ecc.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_trace.h"
++
++static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND);
++#ifdef NOTYET
++static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND);
++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
++ const __u8 *data,
++ const yaffs_Spare *spare);
++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
++ const yaffs_Spare *spare);
++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND);
++#endif
++
++static const char yaffs_countBitsTable[256] = {
++ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
++ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
++};
++
++int yaffs_CountBits(__u8 x)
++{
++ int retVal;
++ retVal = yaffs_countBitsTable[x];
++ return retVal;
++}
++
++/********** Tags ECC calculations *********/
++
++void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
++{
++ yaffs_ECCCalculate(data, spare->ecc1);
++ yaffs_ECCCalculate(&data[256], spare->ecc2);
++}
++
++void yaffs_CalcTagsECC(yaffs_Tags *tags)
++{
++ /* Calculate an ecc */
++
++ unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
++ unsigned i, j;
++ unsigned ecc = 0;
++ unsigned bit = 0;
++
++ tags->ecc = 0;
++
++ for (i = 0; i < 8; i++) {
++ for (j = 1; j & 0xff; j <<= 1) {
++ bit++;
++ if (b[i] & j)
++ ecc ^= bit;
++ }
++ }
++
++ tags->ecc = ecc;
++
++}
++
++int yaffs_CheckECCOnTags(yaffs_Tags *tags)
++{
++ unsigned ecc = tags->ecc;
++
++ yaffs_CalcTagsECC(tags);
++
++ ecc ^= tags->ecc;
++
++ if (ecc && ecc <= 64) {
++ /* TODO: Handle the failure better. Retire? */
++ unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
++
++ ecc--;
++
++ b[ecc / 8] ^= (1 << (ecc & 7));
++
++ /* Now recvalc the ecc */
++ yaffs_CalcTagsECC(tags);
++
++ return 1; /* recovered error */
++ } else if (ecc) {
++ /* Wierd ecc failure value */
++ /* TODO Need to do somethiong here */
++ return -1; /* unrecovered error */
++ }
++
++ return 0;
++}
++
++/********** Tags **********/
++
++static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr,
++ yaffs_Tags *tagsPtr)
++{
++ yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
++
++ yaffs_CalcTagsECC(tagsPtr);
++
++ sparePtr->tagByte0 = tu->asBytes[0];
++ sparePtr->tagByte1 = tu->asBytes[1];
++ sparePtr->tagByte2 = tu->asBytes[2];
++ sparePtr->tagByte3 = tu->asBytes[3];
++ sparePtr->tagByte4 = tu->asBytes[4];
++ sparePtr->tagByte5 = tu->asBytes[5];
++ sparePtr->tagByte6 = tu->asBytes[6];
++ sparePtr->tagByte7 = tu->asBytes[7];
++}
++
++static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,
++ yaffs_Tags *tagsPtr)
++{
++ yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
++ int result;
++
++ tu->asBytes[0] = sparePtr->tagByte0;
++ tu->asBytes[1] = sparePtr->tagByte1;
++ tu->asBytes[2] = sparePtr->tagByte2;
++ tu->asBytes[3] = sparePtr->tagByte3;
++ tu->asBytes[4] = sparePtr->tagByte4;
++ tu->asBytes[5] = sparePtr->tagByte5;
++ tu->asBytes[6] = sparePtr->tagByte6;
++ tu->asBytes[7] = sparePtr->tagByte7;
++
++ result = yaffs_CheckECCOnTags(tagsPtr);
++ if (result > 0)
++ dev->tagsEccFixed++;
++ else if (result < 0)
++ dev->tagsEccUnfixed++;
++}
++
++static void yaffs_SpareInitialise(yaffs_Spare *spare)
++{
++ memset(spare, 0xFF, sizeof(yaffs_Spare));
++}
++
++static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
++ int chunkInNAND, const __u8 *data,
++ yaffs_Spare *spare)
++{
++ if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
++ chunkInNAND));
++ return YAFFS_FAIL;
++ }
++
++ return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
++}
++
++static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
++ int chunkInNAND,
++ __u8 *data,
++ yaffs_Spare *spare,
++ yaffs_ECCResult *eccResult,
++ int doErrorCorrection)
++{
++ int retVal;
++ yaffs_Spare localSpare;
++
++ if (!spare && data) {
++ /* If we don't have a real spare, then we use a local one. */
++ /* Need this for the calculation of the ecc */
++ spare = &localSpare;
++ }
++
++ if (!dev->useNANDECC) {
++ retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
++ if (data && doErrorCorrection) {
++ /* Do ECC correction */
++ /* Todo handle any errors */
++ int eccResult1, eccResult2;
++ __u8 calcEcc[3];
++
++ yaffs_ECCCalculate(data, calcEcc);
++ eccResult1 =
++ yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
++ yaffs_ECCCalculate(&data[256], calcEcc);
++ eccResult2 =
++ yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
++
++ if (eccResult1 > 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>yaffs ecc error fix performed on chunk %d:0"
++ TENDSTR), chunkInNAND));
++ dev->eccFixed++;
++ } else if (eccResult1 < 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>yaffs ecc error unfixed on chunk %d:0"
++ TENDSTR), chunkInNAND));
++ dev->eccUnfixed++;
++ }
++
++ if (eccResult2 > 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>yaffs ecc error fix performed on chunk %d:1"
++ TENDSTR), chunkInNAND));
++ dev->eccFixed++;
++ } else if (eccResult2 < 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>yaffs ecc error unfixed on chunk %d:1"
++ TENDSTR), chunkInNAND));
++ dev->eccUnfixed++;
++ }
++
++ if (eccResult1 || eccResult2) {
++ /* We had a data problem on this page */
++ yaffs_HandleReadDataError(dev, chunkInNAND);
++ }
++
++ if (eccResult1 < 0 || eccResult2 < 0)
++ *eccResult = YAFFS_ECC_RESULT_UNFIXED;
++ else if (eccResult1 > 0 || eccResult2 > 0)
++ *eccResult = YAFFS_ECC_RESULT_FIXED;
++ else
++ *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
++ }
++ } else {
++ /* Must allocate enough memory for spare+2*sizeof(int) */
++ /* for ecc results from device. */
++ struct yaffs_NANDSpare nspare;
++
++ memset(&nspare, 0, sizeof(nspare));
++
++ retVal = dev->readChunkFromNAND(dev, chunkInNAND, data,
++ (yaffs_Spare *) &nspare);
++ memcpy(spare, &nspare, sizeof(yaffs_Spare));
++ if (data && doErrorCorrection) {
++ if (nspare.eccres1 > 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>mtd ecc error fix performed on chunk %d:0"
++ TENDSTR), chunkInNAND));
++ } else if (nspare.eccres1 < 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>mtd ecc error unfixed on chunk %d:0"
++ TENDSTR), chunkInNAND));
++ }
++
++ if (nspare.eccres2 > 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>mtd ecc error fix performed on chunk %d:1"
++ TENDSTR), chunkInNAND));
++ } else if (nspare.eccres2 < 0) {
++ T(YAFFS_TRACE_ERROR,
++ (TSTR
++ ("**>>mtd ecc error unfixed on chunk %d:1"
++ TENDSTR), chunkInNAND));
++ }
++
++ if (nspare.eccres1 || nspare.eccres2) {
++ /* We had a data problem on this page */
++ yaffs_HandleReadDataError(dev, chunkInNAND);
++ }
++
++ if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
++ *eccResult = YAFFS_ECC_RESULT_UNFIXED;
++ else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
++ *eccResult = YAFFS_ECC_RESULT_FIXED;
++ else
++ *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
++
++ }
++ }
++ return retVal;
++}
++
++#ifdef NOTYET
++static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
++ int chunkInNAND)
++{
++ static int init;
++ static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
++ static __u8 data[YAFFS_BYTES_PER_CHUNK];
++ /* Might as well always allocate the larger size for */
++ /* dev->useNANDECC == true; */
++ static __u8 spare[sizeof(struct yaffs_NANDSpare)];
++
++ dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
++
++ if (!init) {
++ memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
++ init = 1;
++ }
++
++ if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
++ return YAFFS_FAIL;
++ if (memcmp(cmpbuf, spare, 16))
++ return YAFFS_FAIL;
++
++ return YAFFS_OK;
++
++}
++#endif
++
++/*
++ * Functions for robustisizing
++ */
++
++static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
++{
++ int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
++
++ /* Mark the block for retirement */
++ yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1;
++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++ (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
++
++ /* TODO:
++ * Just do a garbage collection on the affected block
++ * then retire the block
++ * NB recursion
++ */
++}
++
++#ifdef NOTYET
++static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND)
++{
++}
++
++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
++ const __u8 *data,
++ const yaffs_Spare *spare)
++{
++}
++
++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
++ const yaffs_Spare *spare)
++{
++}
++
++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND)
++{
++ int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
++
++ /* Mark the block for retirement */
++ yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
++ /* Delete the chunk */
++ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
++}
++
++static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1,
++ const yaffs_Spare *s0, const yaffs_Spare *s1)
++{
++
++ if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
++ s0->tagByte0 != s1->tagByte0 ||
++ s0->tagByte1 != s1->tagByte1 ||
++ s0->tagByte2 != s1->tagByte2 ||
++ s0->tagByte3 != s1->tagByte3 ||
++ s0->tagByte4 != s1->tagByte4 ||
++ s0->tagByte5 != s1->tagByte5 ||
++ s0->tagByte6 != s1->tagByte6 ||
++ s0->tagByte7 != s1->tagByte7 ||
++ s0->ecc1[0] != s1->ecc1[0] ||
++ s0->ecc1[1] != s1->ecc1[1] ||
++ s0->ecc1[2] != s1->ecc1[2] ||
++ s0->ecc2[0] != s1->ecc2[0] ||
++ s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
++ return 0;
++ }
++
++ return 1;
++}
++#endif /* NOTYET */
++
++int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
++ int chunkInNAND,
++ const __u8 *data,
++ const yaffs_ExtendedTags *eTags)
++{
++ yaffs_Spare spare;
++ yaffs_Tags tags;
++
++ yaffs_SpareInitialise(&spare);
++
++ if (eTags->chunkDeleted)
++ spare.pageStatus = 0;
++ else {
++ tags.objectId = eTags->objectId;
++ tags.chunkId = eTags->chunkId;
++
++ tags.byteCountLSB = eTags->byteCount & 0x3ff;
++
++ if (dev->nDataBytesPerChunk >= 1024)
++ tags.byteCountMSB = (eTags->byteCount >> 10) & 3;
++ else
++ tags.byteCountMSB = 3;
++
++
++ tags.serialNumber = eTags->serialNumber;
++
++ if (!dev->useNANDECC && data)
++ yaffs_CalcECC(data, &spare);
++
++ yaffs_LoadTagsIntoSpare(&spare, &tags);
++
++ }
++
++ return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
++}
++
++int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
++ int chunkInNAND,
++ __u8 *data,
++ yaffs_ExtendedTags *eTags)
++{
++
++ yaffs_Spare spare;
++ yaffs_Tags tags;
++ yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN;
++
++ static yaffs_Spare spareFF;
++ static int init;
++
++ if (!init) {
++ memset(&spareFF, 0xFF, sizeof(spareFF));
++ init = 1;
++ }
++
++ if (yaffs_ReadChunkFromNAND
++ (dev, chunkInNAND, data, &spare, &eccResult, 1)) {
++ /* eTags may be NULL */
++ if (eTags) {
++
++ int deleted =
++ (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
++
++ eTags->chunkDeleted = deleted;
++ eTags->eccResult = eccResult;
++ eTags->blockBad = 0; /* We're reading it */
++ /* therefore it is not a bad block */
++ eTags->chunkUsed =
++ (memcmp(&spareFF, &spare, sizeof(spareFF)) !=
++ 0) ? 1 : 0;
++
++ if (eTags->chunkUsed) {
++ yaffs_GetTagsFromSpare(dev, &spare, &tags);
++
++ eTags->objectId = tags.objectId;
++ eTags->chunkId = tags.chunkId;
++ eTags->byteCount = tags.byteCountLSB;
++
++ if (dev->nDataBytesPerChunk >= 1024)
++ eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10);
++
++ eTags->serialNumber = tags.serialNumber;
++ }
++ }
++
++ return YAFFS_OK;
++ } else {
++ return YAFFS_FAIL;
++ }
++}
++
++int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
++ int blockInNAND)
++{
++
++ yaffs_Spare spare;
++
++ memset(&spare, 0xff, sizeof(yaffs_Spare));
++
++ spare.blockStatus = 'Y';
++
++ yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
++ &spare);
++ yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
++ NULL, &spare);
++
++ return YAFFS_OK;
++
++}
++
++int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
++ int blockNo,
++ yaffs_BlockState *state,
++ __u32 *sequenceNumber)
++{
++
++ yaffs_Spare spare0, spare1;
++ static yaffs_Spare spareFF;
++ static int init;
++ yaffs_ECCResult dummy;
++
++ if (!init) {
++ memset(&spareFF, 0xFF, sizeof(spareFF));
++ init = 1;
++ }
++
++ *sequenceNumber = 0;
++
++ yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
++ &spare0, &dummy, 1);
++ yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
++ &spare1, &dummy, 1);
++
++ if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
++ *state = YAFFS_BLOCK_STATE_DEAD;
++ else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
++ *state = YAFFS_BLOCK_STATE_EMPTY;
++ else
++ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
++
++ return YAFFS_OK;
++}
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_tagscompat.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_tagscompat.h
+--- linux-2.6.29/fs/yaffs2/yaffs_tagscompat.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_tagscompat.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_TAGSCOMPAT_H__
++#define __YAFFS_TAGSCOMPAT_H__
++
++#include "yaffs_guts.h"
++int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
++ int chunkInNAND,
++ const __u8 *data,
++ const yaffs_ExtendedTags *tags);
++int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
++ int chunkInNAND,
++ __u8 *data,
++ yaffs_ExtendedTags *tags);
++int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
++ int blockNo);
++int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
++ int blockNo,
++ yaffs_BlockState *state,
++ __u32 *sequenceNumber);
++
++void yaffs_CalcTagsECC(yaffs_Tags *tags);
++int yaffs_CheckECCOnTags(yaffs_Tags *tags);
++int yaffs_CountBits(__u8 byte);
++
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_tagsvalidity.c linux-2.6.29-v2010041601/fs/yaffs2/yaffs_tagsvalidity.c
+--- linux-2.6.29/fs/yaffs2/yaffs_tagsvalidity.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_tagsvalidity.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can 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 "yaffs_tagsvalidity.h"
++
++void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
++{
++ memset(tags, 0, sizeof(yaffs_ExtendedTags));
++ tags->validMarker0 = 0xAAAAAAAA;
++ tags->validMarker1 = 0x55555555;
++}
++
++int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
++{
++ return (tags->validMarker0 == 0xAAAAAAAA &&
++ tags->validMarker1 == 0x55555555);
++
++}
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_tagsvalidity.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_tagsvalidity.h
+--- linux-2.6.29/fs/yaffs2/yaffs_tagsvalidity.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_tagsvalidity.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,24 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++
++#ifndef __YAFFS_TAGS_VALIDITY_H__
++#define __YAFFS_TAGS_VALIDITY_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
++int yaffs_ValidateTags(yaffs_ExtendedTags *tags);
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yaffs_trace.h linux-2.6.29-v2010041601/fs/yaffs2/yaffs_trace.h
+--- linux-2.6.29/fs/yaffs2/yaffs_trace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yaffs_trace.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,58 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++
++#ifndef __YTRACE_H__
++#define __YTRACE_H__
++
++extern unsigned int yaffs_traceMask;
++extern unsigned int yaffs_wr_attempts;
++
++/*
++ * Tracing flags.
++ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
++ */
++
++#define YAFFS_TRACE_OS 0x00000002
++#define YAFFS_TRACE_ALLOCATE 0x00000004
++#define YAFFS_TRACE_SCAN 0x00000008
++#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
++#define YAFFS_TRACE_ERASE 0x00000020
++#define YAFFS_TRACE_GC 0x00000040
++#define YAFFS_TRACE_WRITE 0x00000080
++#define YAFFS_TRACE_TRACING 0x00000100
++#define YAFFS_TRACE_DELETION 0x00000200
++#define YAFFS_TRACE_BUFFERS 0x00000400
++#define YAFFS_TRACE_NANDACCESS 0x00000800
++#define YAFFS_TRACE_GC_DETAIL 0x00001000
++#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
++#define YAFFS_TRACE_MTD 0x00004000
++#define YAFFS_TRACE_CHECKPOINT 0x00008000
++
++#define YAFFS_TRACE_VERIFY 0x00010000
++#define YAFFS_TRACE_VERIFY_NAND 0x00020000
++#define YAFFS_TRACE_VERIFY_FULL 0x00040000
++#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
++
++#define YAFFS_TRACE_SYNC 0x00100000
++
++#define YAFFS_TRACE_ERROR 0x40000000
++#define YAFFS_TRACE_BUG 0x80000000
++#define YAFFS_TRACE_ALWAYS 0xF0000000
++
++
++#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
++
++#endif
+diff -Naur linux-2.6.29/fs/yaffs2/yportenv.h linux-2.6.29-v2010041601/fs/yaffs2/yportenv.h
+--- linux-2.6.29/fs/yaffs2/yportenv.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/fs/yaffs2/yportenv.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,166 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2007 Aleph One Ltd.
++ * for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++
++#ifndef __YPORTENV_H__
++#define __YPORTENV_H__
++
++/*
++ * Define the MTD version in terms of Linux Kernel versions
++ * This allows yaffs to be used independantly of the kernel
++ * as well as with it.
++ */
++
++#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
++
++#if defined CONFIG_YAFFS_WINCE
++
++#include "ywinceenv.h"
++
++#elif defined __KERNEL__
++
++#include "moduleconfig.h"
++
++/* Linux kernel */
++
++#include <linux/version.h>
++#define MTD_VERSION_CODE LINUX_VERSION_CODE
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
++#include <linux/config.h>
++#endif
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++
++#define YCHAR char
++#define YUCHAR unsigned char
++#define _Y(x) x
++#define yaffs_strcat(a, b) strcat(a, b)
++#define yaffs_strcpy(a, b) strcpy(a, b)
++#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
++#define yaffs_strncmp(a, b, c) strncmp(a, b, c)
++#define yaffs_strnlen(s,m) strnlen(s,m)
++#define yaffs_sprintf sprintf
++#define yaffs_toupper(a) toupper(a)
++
++#define Y_INLINE inline
++
++#define YAFFS_LOSTNFOUND_NAME "lost+found"
++#define YAFFS_LOSTNFOUND_PREFIX "obj"
++
++/* #define YPRINTF(x) printk x */
++#define YMALLOC(x) kmalloc(x, GFP_NOFS)
++#define YFREE(x) kfree(x)
++#define YMALLOC_ALT(x) vmalloc(x)
++#define YFREE_ALT(x) vfree(x)
++#define YMALLOC_DMA(x) YMALLOC(x)
++
++/* KR - added for use in scan so processes aren't blocked indefinitely. */
++#define YYIELD() schedule()
++
++#define YAFFS_ROOT_MODE 0755
++#define YAFFS_LOSTNFOUND_MODE 0700
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
++#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
++#define Y_TIME_CONVERT(x) (x).tv_sec
++#else
++#define Y_CURRENT_TIME CURRENT_TIME
++#define Y_TIME_CONVERT(x) (x)
++#endif
++
++#define yaffs_SumCompare(x, y) ((x) == (y))
++#define yaffs_strcmp(a, b) strcmp(a, b)
++
++#define TENDSTR "\n"
++#define TSTR(x) KERN_WARNING x
++#define TCONT(x) x
++#define TOUT(p) printk p
++
++#define yaffs_trace(mask, fmt, args...) \
++ do { if ((mask) & (yaffs_traceMask| YAFFS_TRACE_ALWAYS)) \
++ printk(KERN_WARNING "yaffs: " fmt, ## args); \
++ } while (0)
++
++#define compile_time_assertion(assertion) \
++ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
++
++#elif defined CONFIG_YAFFS_DIRECT
++
++#define MTD_VERSION_CODE MTD_VERSION(2, 6, 22)
++
++/* Direct interface */
++#include "ydirectenv.h"
++
++#elif defined CONFIG_YAFFS_UTIL
++
++/* Stuff for YAFFS utilities */
++
++#include "stdlib.h"
++#include "stdio.h"
++#include "string.h"
++
++#include "devextras.h"
++
++#define YMALLOC(x) malloc(x)
++#define YFREE(x) free(x)
++#define YMALLOC_ALT(x) malloc(x)
++#define YFREE_ALT(x) free(x)
++
++#define YCHAR char
++#define YUCHAR unsigned char
++#define _Y(x) x
++#define yaffs_strcat(a, b) strcat(a, b)
++#define yaffs_strcpy(a, b) strcpy(a, b)
++#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
++#define yaffs_strnlen(s,m) strnlen(s,m)
++#define yaffs_sprintf sprintf
++#define yaffs_toupper(a) toupper(a)
++
++#define Y_INLINE inline
++
++/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */
++/* #define YALERT(s) YINFO(s) */
++
++#define TENDSTR "\n"
++#define TSTR(x) x
++#define TOUT(p) printf p
++
++#define YAFFS_LOSTNFOUND_NAME "lost+found"
++#define YAFFS_LOSTNFOUND_PREFIX "obj"
++/* #define YPRINTF(x) printf x */
++
++#define YAFFS_ROOT_MODE 0755
++#define YAFFS_LOSTNFOUND_MODE 0700
++
++#define yaffs_SumCompare(x, y) ((x) == (y))
++#define yaffs_strcmp(a, b) strcmp(a, b)
++
++#else
++/* Should have specified a configuration type */
++#error Unknown configuration
++
++#endif
++
++
++#ifndef YBUG
++#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0)
++#endif
++
++#endif
+diff -Naur linux-2.6.29/.gitignore linux-2.6.29-v2010041601/.gitignore
+--- linux-2.6.29/.gitignore 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/.gitignore 2010-04-13 20:23:26.000000000 +0200
+@@ -64,3 +64,6 @@
+ *.orig
+ *~
+ \#*#
++
++# Source Insight dirs
++si
+diff -Naur linux-2.6.29/include/asm-powerpc/fsldma.h linux-2.6.29-v2010041601/include/asm-powerpc/fsldma.h
+--- linux-2.6.29/include/asm-powerpc/fsldma.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/include/asm-powerpc/fsldma.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,278 @@
++/*
++ * Hongjun Chen <hong-jun.chen@freescale.com>
++ * Copyright (C) Freescale Semicondutor, Inc. 2007, 2008. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the Free
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * The full GNU General Public License is included in this distribution in the
++ * file called COPYING.
++ */
++#ifndef _FSLDMA_H_
++#define _FSLDMA_H_
++
++#include <linux/dmaengine.h>
++#include "fsldma_reg.h"
++#include <linux/init.h>
++#include <linux/dmapool.h>
++#include <linux/cache.h>
++#include <linux/pci_ids.h>
++#include <linux/dmaengine.h>
++
++/* This setting can be changed by user */
++#define MAX_TCD_NUM_PER_CH 200
++
++#define FSL_LOW_COMPLETION_MASK 0xffffffc0
++#define DMA_NO_CHAN -1;
++
++extern struct list_head dma_device_list;
++extern struct list_head dma_client_list;
++
++/* This defines the prototype of callback funtion registered by the drivers */
++typedef void (*fsl_dma_callback_t) (void *arg, int error_status);
++
++/*! This defines the list of device ID's for DMA */
++enum fsl_dma_device {
++ FSL_DMA_MDDRC = 32,
++ FSL_DMA_MBX = 31,
++ FSL_DMA_SDHC = 30,
++ FSL_DMA_NFC = 29,
++ FSL_DMA_PATA_TX = 28,
++ FSL_DMA_PATA_RX = 27,
++ FSL_DMA_LPC = 26,
++ FSL_DMA_SPDIF_RX = 25,
++ FSL_DMA_SPDIF_TX = 24,
++};
++
++struct ch_pri {
++ u8 g_pri; /* The priority of group which this channel locates */
++ u8 ch_pri; /* The priority of this channel */
++ u8 preempt; /* Preemptable by other higher priority channel */
++};
++
++struct fsl_dma_mtcd_buf {
++ void *addr_v;
++ TCD *addr_va; /* Aligned in 32 bytes */
++ dma_addr_t addr_p;
++ dma_addr_t addr_pa; /* Aligned in 32 bytes */
++ size_t size;
++};
++
++/**
++ * struct fsl_device - internal representation of a FSL DMA device
++ * @reg: register space
++ * @tcd: transfer control descriptor space
++ * @common: embedded struct dma_device
++ * @ch_stat: the channel usage status
++ * @arbit_mode: the arbitration mode of group and channel
++ * @chpri: the channel priority, it is a tip for hack.
++ */
++struct fsl_device {
++ fsl_dma_reg *reg;
++ TCD *tcd;
++
++ /* TCDs in SDRAM memory */
++ struct fsl_dma_mtcd_buf mtcd;
++
++ struct dma_device common;
++
++ u32 irq;
++ spinlock_t ch_lock; /* protect channel usage status */
++ u8 ch_stat[FSL_DMA_CH_NUM]; /* the channel usage status */
++
++ u8 arbit_mode; /* the arbitration mode of group and channel,
++ init once */
++};
++
++/**
++ * struct fsl_dma_chan - internal representation of a DMA channel
++ * @device:
++ * @sw_in_use:
++ * @completion:
++ * @completion_low:
++ * @completion_high:
++ * @completed_cookie: last cookie seen completed on cleanup
++ * @cookie: value of last cookie given to client
++ * @last_completion:
++ * @xfercap:
++ * @priority: the
++ * @desc_lock:
++ * @free_desc:
++ * @used_desc:
++ * @resource:
++ * @device_node:
++ */
++
++struct fsl_dma_chan {
++ fsl_dma_callback_t cb_fn; /* The callback function */
++ void *cb_args; /* The argument of callback function */
++
++ int num_buf;
++ int pending;
++
++ struct fsl_device *device;
++ struct dma_chan common;
++
++ int ch_index;
++ struct ch_pri pri;
++
++ u32 status;
++ struct semaphore sem_lock;
++};
++
++/* Arbitration mode of group and channel */
++#define FSL_DMA_GROUP_FIX 0x01
++#define FSL_DMA_CH_FIX 0x02
++
++/* This structure contains the information about a dma transfer */
++struct fsl_dma_requestbuf {
++ dma_addr_t src; /* source address */
++ dma_addr_t dest; /* destination address */
++ size_t soff; /* Source address signed offset */
++ size_t doff; /* Destination address signed offset */
++ size_t minor_loop; /* Number of bytes for every minor loop */
++ size_t len; /* the length of this transfer : bytes */
++};
++
++int fsl_dma_cfg_arbit_mode(int arbit_mode);
++
++/*!
++ * Before this function is called by the driver at open time, function
++ * fsl_dma_cfg_arbit_mode() should be called to configure the arbitration mode
++ * for dma engine. The DMA driver would do any initialization steps that is
++ * required to get the channel ready for data transfer.
++ *
++ * @param channel_id a pre-defined id. The peripheral driver would specify
++ * the id associated with its peripheral. This would be
++ * used by the DMA driver to identify the peripheral
++ * requesting DMA and do the necessary setup on the
++ * channel associated with the particular peripheral.
++ * The DMA driver could use static or dynamic DMA channel
++ * allocation.
++ * @return returns a negative number on error if request for a DMA channel
++ * did not succeed, returns the channel number to be
++ * used on success.
++ */
++int fsl_dma_chan_request(int channel_id);
++
++/*!
++ * This function would just configure the scatterlist specified by the
++ * user into dma channel. This is a slight variation of fsl_dma_config(),
++ * it is provided for the convenience of drivers that have a scatterlist
++ * passed into them. It is the calling driver's responsibility to have the
++ * correct physical address filled in the "dma_address" field of the
++ * scatterlist.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver.
++ * @param sg a scatterlist of buffers. The caller must guarantee
++ * the dma_buf is available until the transfer is
++ * completed.
++ * @param num_buf number of buffers in the array
++ * @param num_of_bytes total number of bytes to transfer. If set to 0, this
++ * would imply to use the length field of the scatterlist
++ * for each DMA transfer. Else it would calculate the size
++ * for each DMA transfer.
++ * @return This function returns a negative number on error if buffer could not
++ * be added with DMA for transfer.
++ * On Success, it returns 0
++ */
++int fsl_dma_sg_config(int channel_num, struct scatterlist *sg,
++ int num_buf, int num_of_bytes);
++
++/*!
++ * This function is generally called by the driver at close time. The DMA
++ * driver would do any cleanup associated with this channel.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver.
++ * @return returns a negative number on error or 0 on success
++ */
++void fsl_dma_free_chan(int channel_num);
++
++/*!
++ * This function would just configure the buffers specified by the user into
++ * dma channel. The caller must call fsl_dma_enable to start this transfer.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver.
++ * @param dma_buf an array of physical addresses to the user defined
++ * buffers. The caller must guarantee the dma_buf is
++ * available until the transfer is completed.
++ * @param num_buf number of buffers in the array
++ * @param mode specifies whether this is READ or WRITE operation
++ * @return This function returns a negative number on error if buffer could
++ * not be added with DMA for transfer.
++ * On Success, it returns 0
++ */
++int fsl_dma_config(int channel_num,
++ struct fsl_dma_requestbuf *dma_buf, int num_buf);
++
++/*!
++ * This function is provided if the driver would like to set/change its
++ * callback function.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver.
++ * @param callback a callback function to provide notification on transfer
++ * completion, user could specify NULL if he does not wish
++ * to be notified
++ * @param arg an argument that gets passed in to the callback
++ * function, used by the user to do any driver specific
++ * operations.
++ * @return this function returns a negative number on error if the callback
++ * could not be set for the channel or 0 on success
++ */
++int fsl_dma_callback_set(int channel_num,
++ fsl_dma_callback_t callback, void *arg);
++
++/*!
++ * This starts DMA transfer. Or it restarts DMA on a stopped channel
++ * previously stopped with fsl_dma_disable().
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver.
++ * @return returns a negative number on error or 0 on success
++ */
++void fsl_dma_enable(int channel_num);
++
++/*!
++ * This stops the DMA channel and any ongoing transfers. Subsequent use of
++ * fsl_dma_enable() will restart the channel and restart the transfer.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver.
++ * @return returns a negative number on error or 0 on success
++ */
++void fsl_dma_disable(int channel_num);
++
++/*!
++ * This indicates what status the channel is.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver.
++ * @return return a negative number on error or zero/positive number on success
++ */
++int fsl_dma_status(int channel_num);
++int fsl_dma_config_priority(int channel_num, struct fsl_dma_requestbuf *dma_buf,
++ int num_buf,unsigned char priority);
++int fsl_dma_up_semaphore(unsigned int channel);
++#endif /* _FSLDMA_H_ */
+diff -Naur linux-2.6.29/include/asm-powerpc/fsldma_reg.h linux-2.6.29-v2010041601/include/asm-powerpc/fsldma_reg.h
+--- linux-2.6.29/include/asm-powerpc/fsldma_reg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/include/asm-powerpc/fsldma_reg.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,172 @@
++/*
++ * Hongjun Chen <hong-jun.chen@freescale.com>
++ * Copyright (C) Freescale Semicondutor, Inc. 2007, 2008. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the Free
++ * Software Foundation; either version 2 of the License, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * The full GNU General Public License is included in this distribution in the
++ * file called COPYING.
++ */
++#ifndef _FSL_REGISTERS_H_
++#define _FSL_REGISTERS_H_
++
++/* Macro definitions */
++#define FSL_DMA_CH_NUM 64 /* Total channel number */
++#define FSL_DMA_DESC_NUM_PER_CH 64 /* Descriptors per channel */
++#define FSL_DMA_CH_NUM_IN_GROUP 16 /* Channel number in one group */
++#define FSL_DMA_GROUP_NUM (FSL_DMA_CH_NUM / FSL_DMA_CH_NUM_IN_GROUP)
++ /* Channel number in one group */
++
++#define FSL_DMA_TCD_OFFSET 0x1000 /* TCD(transfer control descriptor)
++ area offset from IMMR
++ */
++#define FSL_DMA_IRQ 65 /* DMA engine interrupt number */
++
++/* Arbitration mode of group and channel */
++#define FSL_DMA_GROUP_FIX 0x01 /* Fixed group arbitration, 0 for
++ round robin mode
++ */
++#define FSL_DMA_CH_FIX 0x02 /* Fixed channel arbitration, 0 for
++ round robin mode
++ */
++
++#define FSL_DMA_PRI_IN_USE 1 /* Hack: the global structure of
++ priority is in use
++ */
++#define FSL_DMA_PRI_NOT_USE 0 /* Hack: the global structure of
++ priority is free
++ */
++
++/* Register offset macro definitions */
++#define FSL_DMA_DMACR_ERGA_RR (1<<3) /* Enable Round Robin Group
++ Arbitration */
++#define FSL_DMA_DMACR_ERCA_RR (1<<2) /* Enable Round Robin Channel
++ Arbitration */
++
++#define FSL_DMA_GPR3PRI(pri) (pri<<14) /* Channel Group 3 Priority */
++#define FSL_DMA_GPR2PRI(pri) (pri<<12) /* Channel Group 2 Priority */
++#define FSL_DMA_GPR1PRI(pri) (pri<<10) /* Channel Group 1 Priority */
++#define FSL_DMA_GPR0PRI(pri) (pri<<8) /* Channel Group 0 Priority */
++
++#define FSL_DMA_CH_PREEMPT (1<<7) /* Enable channel preemption */
++
++#define FSL_DMA_DMAES_VLD (1<<31) /* At least one DMAERR bit is set */
++#define FSL_DMA_DMAES_GPE (1<<15) /* Group priority error */
++#define FSL_DMA_DMAES_CPE (1<<14) /* Channel priority error */
++#define FSL_DMA_DMAES_ERRCHN(err) \
++ ((err >> 8) & 0x3f) /* Error channel number */
++#define FSL_DMA_DMAES_SAE (1<<7) /* Source address error */
++#define FSL_DMA_DMAES_SOE (1<<6) /* Source offset configuration */
++#define FSL_DMA_DMAES_DAE (1<<5) /* Destination address error */
++#define FSL_DMA_DMAES_DOE (1<<4) /* Destination offset error */
++#define FSL_DMA_DMAES_NCE (1<<3) /* Nbytes/citer config error */
++#define FSL_DMA_DMAES_SGE (1<<2) /* Scatter/gather config error */
++#define FSL_DMA_DMAES_SBE (1<<1) /* Source bus error */
++#define FSL_DMA_DMAES_DBE (1<<0) /* Destination bus error */
++
++/* MPC5121 DMA engine registers */
++typedef struct _fsl_dma_reg {
++ /* 0x00 */
++ u32 dmacr; /* DMA control register */
++ u32 dmaes; /* DMA error status */
++ /* 0x08 */
++ u32 dmaerqh; /* DMA enable request high(channels 63~32) */
++ u32 dmaerql; /* DMA enable request low(channels 31~0) */
++ u32 dmaeeih; /* DMA enable error interrupt high(ch63~32) */
++ u32 dmaeeil; /* DMA enable error interrupt low(ch31~0) */
++ /* 0x18 */
++ u8 dmaserq; /* DMA set enable request */
++ u8 dmacerq; /* DMA clear enable request */
++ u8 dmaseei; /* DMA set enable error interrupt */
++ u8 dmaceei; /* DMA clear enable error interrupt */
++ /* 0x1c */
++ u8 dmacint; /* DMA clear interrupt request */
++ u8 dmacerr; /* DMA clear error */
++ u8 dmassrt; /* DMA set start bit */
++ u8 dmacdne; /* DMA clear DONE status bit */
++ /* 0x20 */
++ u32 dmainth; /* DMA interrupt request high(ch63~32) */
++ u32 dmaintl; /* DMA interrupt request low(ch31~0) */
++ u32 dmaerrh; /* DMA error high(ch63~32) */
++ u32 dmaerrl; /* DMA error low(ch31~0) */
++ /* 0x30 */
++ u32 dmahrsh; /* DMA hw request status high(ch63~32) */
++ u32 dmahrsl; /* DMA hardware request status low(ch31~0) */
++ u32 dmaihsa; /* DMA interrupt high select AXE(ch63~32) */
++ u32 dmailsa; /* DMA interrupt low select AXE(ch31~0) */
++ /* 0x40 ~ 0xff */
++ u32 reserve0[48]; /* Reserved */
++ /* 0x100 */
++ u8 dchpri[FSL_DMA_CH_NUM];
++ /* DMA channels(0~63) priority */
++} __attribute__ ((packed)) fsl_dma_reg;
++
++typedef struct _tcd {
++ /* 0x00 */
++ u32 saddr; /* Source address */
++
++ u32 smod:5; /* Source address modulo */
++ u32 ssize:3; /* Source data transfer size */
++ u32 dmod:5; /* Destination address modulo */
++ u32 dsize:3; /* Destination data transfer size */
++ u32 soff:16; /* Signed source address offset */
++
++ /* 0x08 */
++ u32 nbytes; /* Inner "minor" byte count */
++ u32 slast; /* Last source address adjustment */
++ u32 daddr; /* Destination address */
++
++ /* 0x14 */
++ u32 citer_elink:1; /* Enable channel-to-channel linking on
++ * minor loop complete
++ */
++ u32 citer_linkch:6; /* Link channel for minor loop complete */
++ u32 citer:9; /* Current "major" iteration count */
++ u32 doff:16; /* Signed destination address offset */
++
++ /* 0x18 */
++ u32 dlast_sga; /* Last Destination address adjustment/scatter
++ * gather address
++ */
++
++ /* 0x1c */
++ u32 biter_elink:1; /* Enable channel-to-channel linking on major
++ * loop complete
++ */
++ u32 biter_linkch:6;
++ u32 biter:9; /* Beginning "major" iteration count */
++ u32 bwc:2; /* Bandwidth control */
++ u32 major_linkch:6; /* Link channel number */
++ u32 done:1; /* Channel done */
++ u32 active:1; /* Channel active */
++ u32 major_elink:1; /* Enable channel-to-channel linking on major
++ * loop complete
++ */
++ u32 e_sg:1; /* Enable scatter/gather processing */
++ u32 d_req:1; /* Disable request */
++ u32 int_half:1; /* Enable an interrupt when major counter is
++ * half complete
++ */
++ u32 int_maj:1; /* Enable an interrupt when major iteration
++ * count completes
++ */
++ u32 start:1; /* Channel start */
++} __attribute__ ((packed)) TCD;
++
++typedef struct _fsl_dma_tcd {
++ /* 0x1000 */
++ TCD tcd[FSL_DMA_CH_NUM];
++} fsl_dma_tcd;
++#endif /* _FSL_REGISTERS_H_ */
+diff -Naur linux-2.6.29/include/linux/can/dev.h linux-2.6.29-v2010041601/include/linux/can/dev.h
+--- linux-2.6.29/include/linux/can/dev.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/include/linux/can/dev.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,69 @@
++/*
++ * linux/can/dev.h
++ *
++ * Definitions for CAN controller network devices lib (work in progress)
++ *
++ * $Id$
++ *
++ * Author: Andrey Volkov <avolkov@varma-el.com>
++ * Copyright (c) 2006 Varma Electronics Oy
++ *
++ */
++
++#ifndef CAN_DEVICE_H
++#define CAN_DEVICE_H
++
++#include <linux/version.h>
++#include <linux/can/error.h>
++#include <linux/can/ioctl.h>
++
++struct can_priv {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++ struct net_device_stats net_stats;
++#endif
++ struct can_device_stats can_stats;
++
++ /* can-bus oscillator frequency, in Hz,
++ BE CAREFUL! SOME CONTROLLERS (LIKE SJA1000)
++ FOOLISH ABOUT THIS FRQ (for sja1000 as ex. this
++ clock must be xtal clock divided by 2). */
++ u32 can_sys_clock;
++
++ /* by default max_brp is equal 64,
++ but for a Freescale TouCAN, as ex., it can be 255*/
++ u32 max_brp;
++ /* For the mostly all controllers, max_sjw is equal 4, but
++ some, hmm, CAN implementations hardwared it to 1 */
++ u8 max_sjw;
++
++ u32 baudrate; /* in bauds */
++ struct can_bittime bit_time;
++
++ spinlock_t irq_lock;
++ /* Please hold this lock when touching net_stats/can_stats*/
++ spinlock_t stats_lock;
++
++ can_state_t state;
++ can_mode_t mode;
++ can_ctrlmode_t ctrlmode;
++
++ int (*do_set_bit_time)(struct net_device *dev, struct can_bittime *br);
++ int (*do_get_state) (struct net_device *dev, can_state_t *state);
++ int (*do_set_mode) (struct net_device *dev, can_mode_t mode);
++ int (*do_set_ctrlmode)(struct net_device *dev, can_ctrlmode_t ctrlmode);
++ int (*do_get_ctrlmode)(struct net_device *dev, can_ctrlmode_t *ctrlmode);
++};
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
++#define ND2D(_ndev) (_ndev->class_dev.dev)
++#else
++#define ND2D(_ndev) (_ndev->dev.parent)
++#endif
++
++struct net_device *alloc_candev(int sizeof_priv);
++void free_candev(struct net_device *dev);
++
++int can_calc_bit_time(struct can_priv *can, u32 baudrate,
++ struct can_bittime_std *bit_time);
++
++#endif /* CAN_DEVICE_H */
+diff -Naur linux-2.6.29/include/linux/can/ioctl.h linux-2.6.29-v2010041601/include/linux/can/ioctl.h
+--- linux-2.6.29/include/linux/can/ioctl.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/include/linux/can/ioctl.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,151 @@
++/*
++ * linux/can/ioctl.h
++ *
++ * Definitions for CAN controller setup (work in progress)
++ *
++ * $Id$
++ *
++ * Send feedback to <socketcan-users@lists.berlios.de>
++ *
++ */
++
++#ifndef CAN_IOCTL_H
++#define CAN_IOCTL_H
++
++#include <linux/sockios.h>
++
++
++/* max. 16 private ioctls */
++
++#define SIOCSCANBAUDRATE (SIOCDEVPRIVATE+0)
++#define SIOCGCANBAUDRATE (SIOCDEVPRIVATE+1)
++
++#define SIOCSCANCUSTOMBITTIME (SIOCDEVPRIVATE+2)
++#define SIOCGCANCUSTOMBITTIME (SIOCDEVPRIVATE+3)
++
++#define SIOCSCANMODE (SIOCDEVPRIVATE+4)
++#define SIOCGCANMODE (SIOCDEVPRIVATE+5)
++
++#define SIOCSCANCTRLMODE (SIOCDEVPRIVATE+6)
++#define SIOCGCANCTRLMODE (SIOCDEVPRIVATE+7)
++
++#define SIOCSCANFILTER (SIOCDEVPRIVATE+8)
++#define SIOCGCANFILTER (SIOCDEVPRIVATE+9)
++
++#define SIOCGCANSTATE (SIOCDEVPRIVATE+10)
++#define SIOCGCANSTATS (SIOCDEVPRIVATE+11)
++
++#define SIOCSCANERRORCONFIG (SIOCDEVPRIVATE+12)
++#define SIOCGCANERRORCONFIG (SIOCDEVPRIVATE+13)
++
++/* parameters for ioctls */
++
++/* SIOC[SG]CANBAUDRATE */
++/* baudrate for CAN-controller in bits per second. */
++/* 0 = Scan for baudrate (Autobaud) */
++
++typedef __u32 can_baudrate_t;
++
++
++/* SIOC[SG]CANCUSTOMBITTIME */
++
++typedef enum CAN_BITTIME_TYPE {
++ CAN_BITTIME_STD,
++ CAN_BITTIME_BTR
++} can_bittime_type_t;
++
++/* TSEG1 of controllers usually is a sum of synch_seg (always 1),
++ * prop_seg and phase_seg1, TSEG2 = phase_seg2 */
++
++struct can_bittime_std {
++ __u32 brp; /* baud rate prescaler */
++ __u8 prop_seg; /* from 1 to 8 */
++ __u8 phase_seg1; /* from 1 to 8 */
++ __u8 phase_seg2; /* from 1 to 8 */
++ __u8 sjw:7; /* from 1 to 4 */
++ __u8 sam:1; /* 1 - enable triple sampling */
++};
++
++struct can_bittime_btr {
++ __u8 btr0;
++ __u8 btr1;
++};
++
++struct can_bittime {
++ can_bittime_type_t type;
++ union {
++ struct can_bittime_std std;
++ struct can_bittime_btr btr;
++ };
++};
++
++#define CAN_BAUDRATE_UNCONFIGURED ((__u32) 0xFFFFFFFFU)
++#define CAN_BAUDRATE_UNKNOWN 0
++
++/* SIOC[SG]CANMODE */
++
++typedef __u32 can_mode_t;
++
++#define CAN_MODE_STOP 0
++#define CAN_MODE_START 1
++#define CAN_MODE_SLEEP 2
++
++
++/* SIOC[SG]CANCTRLMODE */
++
++typedef __u32 can_ctrlmode_t;
++
++#define CAN_CTRLMODE_LOOPBACK 0x1
++#define CAN_CTRLMODE_LISTENONLY 0x2
++
++
++/* SIOCGCANFILTER */
++
++typedef __u32 can_filter_t;
++
++/* filter modes (may vary due to controller specific capabilities) */
++#define CAN_FILTER_CAPAB 0 /* get filter type capabilities (32 Bit value) */
++#define CAN_FILTER_MASK_VALUE 1 /* easy bit filter (see struct can_filter) */
++#define CAN_FILTER_SFF_BITMASK 2 /* bitfield with 2048 bit SFF filter */
++ /* filters 3 - 31 currently undefined */
++
++#define CAN_FILTER_MAX 31 /* max. filter type value */
++
++
++/* SIOCGCANSTATE */
++
++typedef __u32 can_state_t;
++
++#define CAN_STATE_ACTIVE 0
++#define CAN_STATE_BUS_WARNING 1
++#define CAN_STATE_BUS_PASSIVE 2
++#define CAN_STATE_BUS_OFF 3
++#define CAN_STATE_SCANNING_BAUDRATE 4
++#define CAN_STATE_STOPPED 5
++#define CAN_STATE_SLEEPING 6
++
++
++/* SIOCGCANSTATS */
++
++struct can_device_stats {
++ int error_warning;
++ int data_overrun;
++ int wakeup;
++ int bus_error;
++ int error_passive;
++ int arbitration_lost;
++ int restarts;
++ int bus_error_at_init;
++};
++
++/* SIOC[SG]CANERRORCONFIG */
++
++typedef enum CAN_ERRCFG_TYPE {
++ CAN_ERRCFG_MASK,
++ CAN_ERRCFG_BUSERR,
++ CAN_ERRCFG_BUSOFF
++} can_errcfg_type_t;
++
++/* tbd */
++
++#endif /* CAN_IOCTL_H */
+diff -Naur linux-2.6.29/include/linux/can/version.h linux-2.6.29-v2010041601/include/linux/can/version.h
+--- linux-2.6.29/include/linux/can/version.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/include/linux/can/version.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,22 @@
++/*
++ * linux/can/version.h
++ *
++ * Version information for the CAN network layer implementation
++
++ * Author: Urs Thuermann <urs.thuermann@volkswagen.de>
++ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
++ * All rights reserved.
++ *
++ * Send feedback to <socketcan-users@lists.berlios.de>
++ *
++ */
++
++#ifndef CAN_VERSION_H
++#define CAN_VERSION_H
++
++#define RCSID(s) asm(".section .rodata.str1.1,\"aMS\",@progbits,1\n\t" \
++ ".string \"" s "\"\n\t.previous\n")
++
++RCSID("$Id$");
++
++#endif /* CAN_VERSION_H */
+diff -Naur linux-2.6.29/include/linux/fsl_devices.h linux-2.6.29-v2010041601/include/linux/fsl_devices.h
+--- linux-2.6.29/include/linux/fsl_devices.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/include/linux/fsl_devices.h 2010-04-13 20:23:26.000000000 +0200
+@@ -14,6 +14,7 @@
+ * option) any later version.
+ */
+
++#ifdef __KERNEL__
+ #ifndef _FSL_DEVICE_H_
+ #define _FSL_DEVICE_H_
+
+@@ -47,7 +48,11 @@
+ struct gianfar_platform_data {
+ /* device specific information */
+ u32 device_flags;
+- char bus_id[BUS_ID_SIZE];
++ /* board specific information */
++ u32 board_flags;
++ u32 bus_id;
++ u32 phy_id;
++ u8 mac_addr[6];
+ phy_interface_t interface;
+ };
+
+@@ -56,6 +61,16 @@
+ int irq[32];
+ };
+
++/* Flags related to gianfar device features */
++#define FSL_GIANFAR_DEV_HAS_GIGABIT 0x00000001
++#define FSL_GIANFAR_DEV_HAS_COALESCE 0x00000002
++#define FSL_GIANFAR_DEV_HAS_RMON 0x00000004
++#define FSL_GIANFAR_DEV_HAS_MULTI_INTR 0x00000008
++#define FSL_GIANFAR_DEV_HAS_CSUM 0x00000010
++#define FSL_GIANFAR_DEV_HAS_VLAN 0x00000020
++#define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH 0x00000040
++#define FSL_GIANFAR_DEV_HAS_PADDING 0x00000080
++
+ /* Flags in gianfar_platform_data */
+ #define FSL_GIANFAR_BRD_HAS_PHY_INTR 0x00000001 /* set or use a timer */
+ #define FSL_GIANFAR_BRD_IS_REDUCED 0x00000002 /* Set if RGMII, RMII */
+@@ -84,11 +99,38 @@
+ FSL_USB2_PHY_SERIAL,
+ };
+
++struct platform_device;
+ struct fsl_usb2_platform_data {
+ /* board specific information */
+ enum fsl_usb2_operating_modes operating_mode;
+ enum fsl_usb2_phy_modes phy_mode;
+ unsigned int port_enables;
++
++ char *name; /* pretty print */
++ int (*platform_init) (struct platform_device *);
++ void (*platform_uninit) (struct fsl_usb2_platform_data *);
++ u32 r_start; /* start of MEM resource */
++ u32 r_len; /* length of MEM resource */
++ void __iomem *regs; /* ioremap'd register base */
++ unsigned power_budget; /* for hcd->power_budget */
++ unsigned big_endian_mmio : 1;
++ unsigned big_endian_desc : 1;
++ unsigned es : 1; /* need USBMODE:ES */
++ unsigned have_sysif_regs : 1;
++ unsigned le_setup_buf : 1;
++ unsigned suspended : 1;
++ unsigned already_suspended : 1;
++
++ /* register save area for suspend/resume */
++ u32 pm_command;
++ u32 pm_status;
++ u32 pm_intr_enable;
++ u32 pm_frame_index;
++ u32 pm_segment;
++ u32 pm_frame_list;
++ u32 pm_async_next;
++ u32 pm_configured_flag;
++ u32 pm_portsc;
+ };
+
+ /* Flags in fsl_usb2_mph_platform_data */
+@@ -111,10 +153,5 @@
+ int(*voltage_set)(int slot, int vcc, int vpp);
+ };
+
+-/* Returns non-zero if the current suspend operation would
+- * lead to a deep sleep (i.e. power removed from the core,
+- * instead of just the clock).
+- */
+-int fsl_deep_sleep(void);
+-
+ #endif /* _FSL_DEVICE_H_ */
++#endif /* __KERNEL__ */
+diff -Naur linux-2.6.29/include/linux/i2c/chacha_mt4.h linux-2.6.29-v2010041601/include/linux/i2c/chacha_mt4.h
+--- linux-2.6.29/include/linux/i2c/chacha_mt4.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/include/linux/i2c/chacha_mt4.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,20 @@
++#ifndef __LINUX_I2C_CHACHA_MT4_H
++#define __LINUX_I2C_CHACHA_MT4_H
++
++/* linux/i2c/chacha_mt4.h */
++
++struct chacha_mt4_platform_data {
++ u16 model; /* 2007. */
++ int gpio;
++
++ int (*get_pendown_state)(void);
++ void (*clear_penirq)(void); /* If needed, clear 2nd level
++ interrupt source */
++ int (*if_penirq)(void);
++ void (*enable_irq)(int);
++ int (*init_platform_hw)(void);
++ void (*exit_platform_hw)(void);
++ void (*gpio_attb)(int);
++};
++
++#endif
+diff -Naur linux-2.6.29/include/linux/i2c/ma17p0x.h linux-2.6.29-v2010041601/include/linux/i2c/ma17p0x.h
+--- linux-2.6.29/include/linux/i2c/ma17p0x.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/include/linux/i2c/ma17p0x.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,20 @@
++#ifndef __LINUX_I2C_MA17P0X_H
++#define __LINUX_I2C_MA17P0X_H
++
++/* linux/i2c/ma17p0x.h */
++
++struct ma17p0x_platform_data {
++ u16 model; /* 2007. */
++ int gpio;
++
++ int (*get_pendown_state)(void);
++ void (*clear_penirq)(void); /* If needed, clear 2nd level
++ interrupt source */
++ int (*if_penirq)(void);
++ void (*enable_irq)(int);
++ int (*init_platform_hw)(void);
++ void (*exit_platform_hw)(void);
++ void (*gpio_attb)(int);
++};
++
++#endif
+diff -Naur linux-2.6.29/include/linux/mtd/nand.h linux-2.6.29-v2010041601/include/linux/mtd/nand.h
+--- linux-2.6.29/include/linux/mtd/nand.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/include/linux/mtd/nand.h 2010-04-13 20:23:26.000000000 +0200
+@@ -43,8 +43,8 @@
+ * is supported now. If you add a chip with bigger oobsize/page
+ * adjust this accordingly.
+ */
+-#define NAND_MAX_OOBSIZE 64
+-#define NAND_MAX_PAGESIZE 2048
++#define NAND_MAX_OOBSIZE (64<<1)
++#define NAND_MAX_PAGESIZE (2048<<1)
+
+ /*
+ * Constants for hardware specific CLE/ALE/NCE function
+diff -Naur linux-2.6.29/include/mtd/mtd-abi.h linux-2.6.29-v2010041601/include/mtd/mtd-abi.h
+--- linux-2.6.29/include/mtd/mtd-abi.h 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/include/mtd/mtd-abi.h 2010-04-13 20:23:26.000000000 +0200
+@@ -117,7 +117,7 @@
+ */
+ struct nand_ecclayout {
+ uint32_t eccbytes;
+- uint32_t eccpos[64];
++ uint32_t eccpos[128];
+ uint32_t oobavail;
+ struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
+ };
+diff -Naur linux-2.6.29/kernel/power/main.c linux-2.6.29-v2010041601/kernel/power/main.c
+--- linux-2.6.29/kernel/power/main.c 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/kernel/power/main.c 2010-04-13 20:23:26.000000000 +0200
+@@ -331,15 +331,11 @@
+ goto Close;
+ }
+ suspend_console();
+- suspend_test_start();
+ error = device_suspend(PMSG_SUSPEND);
+ if (error) {
+ printk(KERN_ERR "PM: Some devices failed to suspend\n");
+- goto Recover_platform;
++ goto Resume_console;
+ }
+- suspend_test_finish("suspend devices");
+- if (suspend_test(TEST_DEVICES))
+- goto Recover_platform;
+
+ if (suspend_ops->prepare) {
+ error = suspend_ops->prepare();
+@@ -347,11 +343,10 @@
+ goto Resume_devices;
+ }
+
+- if (suspend_test(TEST_PLATFORM))
+- goto Finish;
++
+
+ error = disable_nonboot_cpus();
+- if (!error && !suspend_test(TEST_CPUS))
++ if (!error )
+ suspend_enter(state);
+
+ enable_nonboot_cpus();
+@@ -359,19 +354,19 @@
+ if (suspend_ops->finish)
+ suspend_ops->finish();
+ Resume_devices:
+- suspend_test_start();
+ device_resume(PMSG_RESUME);
+- suspend_test_finish("resume devices");
++ Resume_console:
+ resume_console();
+ Close:
+ if (suspend_ops->end)
+ suspend_ops->end();
+ return error;
+-
++/*
+ Recover_platform:
+ if (suspend_ops->recover)
+ suspend_ops->recover();
+ goto Resume_devices;
++ */
+ }
+
+ /**
+diff -Naur linux-2.6.29/Makefile linux-2.6.29-v2010041601/Makefile
+--- linux-2.6.29/Makefile 2011-02-27 13:58:59.000000000 +0100
++++ linux-2.6.29-v2010041601/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -190,8 +190,11 @@
+ # Default value for CROSS_COMPILE is not to prefix executables
+ # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
+ export KBUILD_BUILDHOST := $(SUBARCH)
+-ARCH ?= $(SUBARCH)
+-CROSS_COMPILE ?=
++#ARCH ?= $(SUBARCH)
++#CROSS_COMPILE ?=
++
++ARCH ?= powerpc
++CROSS_COMPILE ?= powerpc-e300c3-linux-gnu-
+
+ # Architecture as present in compile.h
+ UTS_MACHINE := $(ARCH)
+diff -Naur linux-2.6.29/net/can/dev.c linux-2.6.29-v2010041601/net/can/dev.c
+--- linux-2.6.29/net/can/dev.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/net/can/dev.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,289 @@
++/*
++ * $Id$
++ *
++ * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
++ * Copyright (C) 2006 Andrey Volkov, Varma Electronics
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the version 2 of the GNU General Public License
++ * as published by the Free Software Foundation
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <linux/if_arp.h>
++#include <linux/can.h>
++#include <linux/can/dev.h>
++
++MODULE_DESCRIPTION("CAN netdevice library");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Marc Kleine-Budde <mkl@pengutronix.de>, "
++ "Andrey Volkov <avolkov@varma-el.com>");
++
++/*
++ Abstract:
++ Baud rate calculated with next formula:
++ baud = frq/(brp*(1 + prop_seg+ phase_seg1 + phase_seg2))
++
++ This calc function based on work of Florian Hartwich and Armin Bassemi
++ "The Configuration of the CAN Bit Timing"
++ (http://www.semiconductors.bosch.de/pdf/CiA99Paper.pdf)
++
++ Parameters:
++ [in]
++ bit_time_nsec - expected bit time in nanosecs
++
++ [out]
++ bit_time - calculated time segments, for meaning of
++ each field read CAN standard.
++*/
++
++#define DEFAULT_MAX_BRP 64U
++#define DEFAULT_MAX_SJW 4U
++
++/* All below values in tq units */
++#define MAX_BIT_TIME 25U
++#define MIN_BIT_TIME 8U
++#define MAX_PROP_SEG 8U
++#define MAX_PHASE_SEG1 8U
++#define MAX_PHASE_SEG2 8U
++
++int can_calc_bit_time(struct can_priv *can, u32 baudrate,
++ struct can_bittime_std *bit_time)
++{
++ int best_error = -200; /* Ariphmetic error */
++ int df, best_df = -200; /* oscillator's tolerance range, greater is better*/
++ u32 quanta; /*in tq units*/
++ u32 brp, phase_seg1, phase_seg2, sjw, prop_seg;
++ u32 brp_min, brp_max, brp_expected;
++ u64 tmp;
++
++ /* baudrate range [1baud,1Mbaud] */
++ if (baudrate == 0 || baudrate > 1000000UL)
++ return -EINVAL;
++
++ tmp = (u64)can->can_sys_clock*1000;
++ do_div(tmp, baudrate);
++ brp_expected = (u32)tmp;
++
++ brp_min = brp_expected / (1000 * MAX_BIT_TIME);
++ if (brp_min == 0)
++ brp_min = 1;
++ if (brp_min > can->max_brp)
++ return -ERANGE;
++
++ brp_max = (brp_expected + 500 * MIN_BIT_TIME) / (1000 * MIN_BIT_TIME);
++ if (brp_max == 0)
++ brp_max = 1;
++ if (brp_max > can->max_brp)
++ brp_max = can->max_brp;
++
++ for (brp = brp_min; brp <= brp_max; brp++) {
++ quanta = brp_expected / (brp * 1000);
++ if (quanta < MAX_BIT_TIME && quanta * brp * 1000 != brp_expected)
++ quanta++;
++ if (quanta < MIN_BIT_TIME || quanta > MAX_BIT_TIME)
++ continue;
++
++ phase_seg2 = min((quanta - 3) / 2, MAX_PHASE_SEG2);
++ for (sjw = can->max_sjw; sjw > 0; sjw--) {
++ for (; phase_seg2 > sjw; phase_seg2--) {
++ u32 err1, err2;
++ phase_seg1 = phase_seg2 % 2 ? phase_seg2-1 : phase_seg2;
++ prop_seg = quanta-1 - phase_seg2 - phase_seg1;
++ /*
++ * FIXME: support of longer lines (i.e. bigger prop_seg)
++ * is more prefered than support of cheap oscillators
++ * (i.e. bigger df/phase_seg1/phase_seg2)
++ */
++ if (prop_seg < phase_seg1)
++ continue;
++ if (prop_seg > MAX_PROP_SEG)
++ goto next_brp;
++
++ err1 = phase_seg1*brp*500*1000/
++ (13*brp_expected-phase_seg2*brp*1000);
++ err2 = sjw*brp*50*1000/brp_expected;
++
++ df = min(err1,err2);
++ if (df >= best_df) {
++ unsigned error = abs(brp_expected*10/
++ (brp*(1+prop_seg+phase_seg1+phase_seg2))-10000);
++
++ if ( error > abs(best_error))
++ continue;
++
++ if (error == best_error && prop_seg < bit_time->prop_seg)
++ continue;
++
++ best_error = error;
++ best_df = df;
++ bit_time->brp = brp;
++ bit_time->prop_seg = prop_seg;
++ bit_time->phase_seg1 = phase_seg1;
++ bit_time->phase_seg2 = phase_seg2;
++ bit_time->sjw = sjw;
++ bit_time->sam = (bit_time->phase_seg1 > 3);
++ }
++ }
++ }
++ next_brp: ;
++ }
++
++ if (best_error < 0)
++ return -EDOM;
++ return 0;
++}
++EXPORT_SYMBOL(can_calc_bit_time);
++
++static int can_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++ struct can_priv *can = netdev_priv(dev);
++ struct can_bittime *bt = (struct can_bittime *)&ifr->ifr_ifru;
++ ulong *baudrate = (ulong *)&ifr->ifr_ifru;
++ int ret = -EOPNOTSUPP;
++
++ dev_dbg(ND2D(dev), "(%s) 0x%08x %p\n", __FUNCTION__, cmd, &ifr->ifr_ifru);
++
++ switch (cmd) {
++ case SIOCSCANBAUDRATE:
++ if (can->do_set_bit_time) {
++ struct can_bittime bit_time;
++ ret = can_calc_bit_time(can, *baudrate, &bit_time.std);
++ if (ret != 0)
++ break;
++ bit_time.type = CAN_BITTIME_STD;
++ ret = can->do_set_bit_time(dev, &bit_time);
++ if (!ret) {
++ can->baudrate = *baudrate;
++ can->bit_time = bit_time;
++ }
++ }
++ break;
++ case SIOCGCANBAUDRATE:
++ *baudrate = can->baudrate;
++ ret = 0;
++ break;
++ case SIOCSCANCUSTOMBITTIME:
++ if (can->do_set_bit_time) {
++ ret = can->do_set_bit_time(dev, bt);
++ if (!ret) {
++ can->bit_time = *bt;
++ if (bt->type == CAN_BITTIME_STD && bt->std.brp) {
++ can->baudrate = can->can_sys_clock/(bt->std.brp*
++ (1+bt->std.prop_seg+bt->std.phase_seg1+bt->std.phase_seg2));
++ } else
++ can->baudrate = CAN_BAUDRATE_UNKNOWN;
++ }
++ }
++ break;
++ case SIOCGCANCUSTOMBITTIME:
++ *bt = can->bit_time;
++ ret = 0;
++ break;
++ case SIOCSCANMODE:
++ if (can->do_set_mode) {
++ can_mode_t mode = *((can_mode_t *)(&ifr->ifr_ifru));
++ if (mode == CAN_MODE_START &&
++ can->baudrate == CAN_BAUDRATE_UNCONFIGURED) {
++ dev_info(ND2D(dev), "Impossible to start on UNKNOWN speed\n");
++ ret = EINVAL;
++ } else
++ return can->do_set_mode(dev, mode);
++ }
++ break;
++ case SIOCGCANMODE:
++ *((can_mode_t *)(&ifr->ifr_ifru)) = can->mode;
++ ret = 0;
++ break;
++ case SIOCSCANCTRLMODE:
++ if (can->do_set_ctrlmode) {
++ can_ctrlmode_t ctrlmode = *((can_ctrlmode_t *)(&ifr->ifr_ifru));
++ return can->do_set_ctrlmode(dev, ctrlmode);
++ }
++ break;
++ case SIOCGCANCTRLMODE:
++ *((can_ctrlmode_t *)(&ifr->ifr_ifru)) = can->ctrlmode;
++ ret = 0;
++ break;
++ case SIOCSCANFILTER:
++ break;
++ case SIOCGCANFILTER:
++ break;
++ case SIOCGCANSTATE:
++ if (can->do_get_state)
++ return can->do_get_state(dev, (can_state_t *)(&ifr->ifr_ifru));
++ break;
++ case SIOCGCANSTATS:
++ *((struct can_device_stats *)(&ifr->ifr_ifru)) = can->can_stats;
++ ret = 0;
++ break;
++ }
++
++ return ret;
++}
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++static struct net_device_stats *can_get_stats(struct net_device *dev)
++{
++ struct can_priv *priv = netdev_priv(dev);
++
++ return &priv->net_stats;
++}
++#endif
++
++static void can_setup(struct net_device *dev)
++{
++ dev->type = ARPHRD_CAN;
++ dev->mtu = sizeof(struct can_frame);
++ dev->do_ioctl = can_ioctl;
++ dev->hard_header_len = 0;
++ dev->addr_len = 0;
++ dev->tx_queue_len = 10;
++
++ /* New-style flags. */
++ dev->flags = IFF_NOARP;
++ dev->features = NETIF_F_NO_CSUM;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++ dev->get_stats = can_get_stats;
++#endif
++}
++
++/*
++ * Function alloc_candev
++ * Allocates and sets up an CAN device
++ */
++struct net_device *alloc_candev(int sizeof_priv)
++{
++ struct net_device *dev;
++ struct can_priv *priv;
++
++ dev = alloc_netdev(sizeof_priv, "can%d", can_setup);
++ if (!dev)
++ return NULL;
++
++ priv = netdev_priv(dev);
++
++ priv->baudrate = CAN_BAUDRATE_UNCONFIGURED;
++ priv->max_brp = DEFAULT_MAX_BRP;
++ priv->max_sjw = DEFAULT_MAX_SJW;
++ spin_lock_init(&priv->irq_lock);
++
++ return dev;
++}
++EXPORT_SYMBOL(alloc_candev);
++
++void free_candev(struct net_device *dev)
++{
++ free_netdev(dev);
++}
++EXPORT_SYMBOL(free_candev);
+diff -Naur linux-2.6.29/net/can/Makefile linux-2.6.29-v2010041601/net/can/Makefile
+--- linux-2.6.29/net/can/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/net/can/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -10,3 +10,5 @@
+
+ obj-$(CONFIG_CAN_BCM) += can-bcm.o
+ can-bcm-objs := bcm.o
++obj-$(CONFIG_CAN) += candev.o
++candev-objs := dev.o
+diff -Naur linux-2.6.29/scripts/setlocalversion linux-2.6.29-v2010041601/scripts/setlocalversion
+--- linux-2.6.29/scripts/setlocalversion 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/scripts/setlocalversion 2010-04-13 20:23:26.000000000 +0200
+@@ -1,65 +1,2 @@
+ #!/bin/sh
+-# Print additional version information for non-release trees.
+
+-usage() {
+- echo "Usage: $0 [srctree]" >&2
+- exit 1
+-}
+-
+-cd "${1:-.}" || usage
+-
+-# Check for git and a git repo.
+-if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
+- # Do we have an untagged version?
+- if git name-rev --tags HEAD | grep -E '^HEAD[[:space:]]+(.*~[0-9]*|undefined)$' > /dev/null; then
+- if tag=`git describe 2>/dev/null`; then
+- echo $tag | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
+- else
+- printf '%s%s' -g $head
+- fi
+- fi
+-
+- # Is this git on svn?
+- if git config --get svn-remote.svn.url >/dev/null; then
+- printf -- '-svn%s' "`git-svn find-rev $head`"
+- fi
+-
+- # Are there uncommitted changes?
+- git update-index --refresh --unmerged > /dev/null
+- if git diff-index --name-only HEAD | grep -v "^scripts/package" \
+- | read dummy; then
+- printf '%s' -dirty
+- fi
+-
+- # All done with git
+- exit
+-fi
+-
+-# Check for mercurial and a mercurial repo.
+-if hgid=`hg id 2>/dev/null`; then
+- tag=`printf '%s' "$hgid" | cut -d' ' -f2`
+-
+- # Do we have an untagged version?
+- if [ -z "$tag" -o "$tag" = tip ]; then
+- id=`printf '%s' "$hgid" | sed 's/[+ ].*//'`
+- printf '%s%s' -hg "$id"
+- fi
+-
+- # Are there uncommitted changes?
+- # These are represented by + after the changeset id.
+- case "$hgid" in
+- *+|*+\ *) printf '%s' -dirty ;;
+- esac
+-
+- # All done with mercurial
+- exit
+-fi
+-
+-# Check for svn and a svn repo.
+-if rev=`svn info 2>/dev/null | grep '^Last Changed Rev'`; then
+- rev=`echo $rev | awk '{print $NF}'`
+- printf -- '-svn%s' "$rev"
+-
+- # All done with svn
+- exit
+-fi
+diff -Naur linux-2.6.29/sound/soc/fsl/Kconfig linux-2.6.29-v2010041601/sound/soc/fsl/Kconfig
+--- linux-2.6.29/sound/soc/fsl/Kconfig 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/sound/soc/fsl/Kconfig 2010-04-13 20:23:26.000000000 +0200
+@@ -25,3 +25,39 @@
+ select PPC_BESTCOMM_GEN_BD
+ help
+ Say Y here to support the MPC5200 PSCs in I2S mode.
++
++menu "ALSA SoC audio for Freescale SOCs"
++
++config SND_SOC_MPC5121
++ bool "ALSA SoC support for the MPC5121 SOC"
++ depends on SND_SOC && PPC_MPC512x
++ default y if PPC_MPC512x
++ help
++ Say Y if you want to add support for codecs attached to a PSC running
++ in I2S/AC97 mode on an MPC5121
++
++choice
++ prompt "ADS5121 Codec Type"
++ depends on SND_SOC_MPC5121
++ default SND_SOC_MPC5121_ADS
++
++config SND_SOC_MPC5121_ADS
++ bool "ADS5121 board with AC97 codec"
++ select SND_SOC_AC97_CODEC
++ select SND_AC97_CODEC
++ help
++ Say Y if you want to enable audio using the LM4550B AC97 codec on a
++ MPC5121ADS, please check your hardware to learn which type of codec
++ is used, and describe it correctly in device tree.
++
++config SND_SOC_MPC5121_I2S
++ bool "ADS5121 board with AD1938 I2S codec"
++ select SND_SOC_AD1939
++ help
++ Say Y if you want to enable audio using the AD1938 I2S codec on a
++ modified MPC5121ADS board.
++
++endchoice
++
++
++endmenu
+diff -Naur linux-2.6.29/sound/soc/fsl/Makefile linux-2.6.29-v2010041601/sound/soc/fsl/Makefile
+--- linux-2.6.29/sound/soc/fsl/Makefile 2009-03-24 00:12:14.000000000 +0100
++++ linux-2.6.29-v2010041601/sound/soc/fsl/Makefile 2010-04-13 20:23:26.000000000 +0200
+@@ -9,3 +9,11 @@
+
+ obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
+
++# MPC5121 ADS Machine Support
++obj-$(CONFIG_SND_SOC_MPC5121_ADS) += mpc5121_ads.o mpc5121_ac97.o
++
++# Modified MPC5121 ADS I2S Machine Support
++obj-$(CONFIG_SND_SOC_MPC5121_I2S) += mpc5121_i2s.o
++
++# MPC5121 Platform Support
++obj-$(CONFIG_SND_SOC_MPC5121) += mpc5121_psc.o mpc5121_pcm.o
+diff -Naur linux-2.6.29/sound/soc/fsl/mpc5121_ac97.c linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_ac97.c
+--- linux-2.6.29/sound/soc/fsl/mpc5121_ac97.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_ac97.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,202 @@
++/*
++ * Copyright 2007,2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ * Freescale AC97 SoC device driver for CPU MPC5121
++ *
++ * Author: Hongjun Chen <hong-jun.chen@freescale.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ */
++#include <linux/delay.h>
++#include <linux/mutex.h>
++#include <sound/ac97_codec.h>
++#include <sound/soc.h>
++#include <sound/soc-dai.h>
++#include <asm/mpc52xx_psc.h>
++#include "mpc5121_psc_info.h"
++
++/* AC97CMD register bit definitions */
++#define RD_FLG (1 << 31)
++#define CTRL_REG_INDEX(reg) (reg << 24)
++#define CMD_DATA(data) (data << 8)
++#define RD_CMD(reg, data) (RD_FLG | CTRL_REG_INDEX(reg) | CMD_DATA(data))
++#define WR_CMD(reg, data) (CTRL_REG_INDEX(reg) | CMD_DATA(data))
++
++/* SR(status register) bit definitions */
++enum {
++ UNEX_RX_SLOT = (1 << 0),
++ DATA_VALID = (1 << 1),
++ DATA_OVR = (1 << 2),
++ CMD_SEND = (1 << 3),
++ ERR_PSC = (1 << 6),
++ UNDER_RUN_ERR = (1 << 11),
++ OVER_RUN_ERR = (1 << 12),
++};
++
++static DEFINE_MUTEX(car_mutex);
++
++unsigned short mpc5121_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
++{
++ unsigned short val = 0;
++ struct mpc52xx_psc *psc_reg;
++ u32 temp, r, v;
++ int timeout = 5000;
++ int retries = 10;
++
++ /* For mysterious cause, this delay time is needed to right
++ * access of codec's register
++ */
++ udelay(40);
++ mutex_lock(&car_mutex);
++
++ psc_reg = psc_reg_priv;
++
++ /* Make sure status data register is empty */
++#ifdef CONFIG_MPC5125_TWR
++ while (in_be16(&psc_reg->mpc52xx_psc_status) & DATA_VALID)
++ temp = in_be32(&psc_reg->ac97data);
++
++ /* Write READ register command in slot0 and 1 */
++ out_be32(&psc_reg->ac97cmd, RD_CMD(reg, val));
++
++ /* Wait for the transmission to complete */
++ do {
++ temp = in_be16(&psc_reg->mpc52xx_psc_status);
++ } while ((temp & CMD_SEND) && timeout--);
++#else
++ while (in_be16(&psc_reg->sr_csr.status) & DATA_VALID)
++ temp = in_be32(&psc_reg->ac97_data);
++
++ /* Write READ register command in slot0 and 1 */
++ out_be32(&psc_reg->ac97_cmd, RD_CMD(reg, val));
++
++ /* Wait for the transmission to complete */
++ do {
++ temp = in_be16(&psc_reg->sr_csr.status);
++ } while ((temp & CMD_SEND) && timeout--);
++#endif
++ if (timeout <= 0) {
++ printk(KERN_ERR "Err: timeout on slot 1 TX busy\n");
++ temp = ~0;
++ goto out;
++ }
++
++ /*
++ * Give the AC'97 codec more than enough time
++ * to respond. (42us = ~2 frames at 48kHz.)
++ */
++ udelay(42);
++
++ /* Wait for data */
++ timeout = 80000;
++ do {
++ cond_resched();
++#ifdef CONFIG_MPC5125_TWR
++ temp = in_be16(&psc_reg->mpc52xx_psc_status);
++#else
++ temp = in_be16(&psc_reg->sr_csr.status);
++#endif
++ } while (!(temp & DATA_VALID) && timeout--);
++
++ if (timeout <= 0 && !(temp & DATA_VALID)) {
++ printk(KERN_ERR "Err: timeout on RX valid\n");
++ temp = ~0;
++ goto out;
++ }
++
++ do {
++#ifdef CONFIG_MPC5125_TWR
++ temp = in_be32(&psc_reg->ac97data);
++#else
++ temp = in_be32(&psc_reg->ac97_data);
++#endif
++ r = (temp >> 24) & 0x7f;
++ v = (temp >> 8) & 0xffff;
++ if (r == reg) {
++ temp = v;
++ break;
++ } else if (--retries) {
++ printk(KERN_ERR "ac97 read back fail. retry\n");
++ printk(KERN_ERR "%s, ac97_data = 0x%08x\n",
++ __func__, temp);
++ continue;
++ } else {
++ printk(KERN_ERR "wrong ac97 register read back "
++ "(%x != %x)\n",
++ r, reg);
++ temp = ~0;
++ }
++ } while (retries);
++
++out:
++ mutex_unlock(&car_mutex);
++ return temp;
++}
++
++void mpc5121_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
++ unsigned short val)
++{
++ struct mpc52xx_psc *psc_reg;
++ int timeout = 5000;
++ u32 temp;
++
++ /* For mysterious cause, this delay time is needed to right
++ * access of codec's register
++ */
++ udelay(40);
++ mutex_lock(&car_mutex);
++
++ psc_reg = psc_reg_priv;
++
++ /* Write READ register command in slot0 and 1 */
++#ifdef CONFIG_MPC5125_TWR
++ psc_reg->ac97cmd = WR_CMD(reg, val);
++#else
++ psc_reg->ac97_cmd = WR_CMD(reg, val);
++#endif
++
++ /*
++ * Wait for the transmission of both slots to complete.
++ */
++ do {
++#ifdef CONFIG_MPC5125_TWR
++ temp = psc_reg->mpc52xx_psc_status;
++#else
++ temp = psc_reg->sr_csr.status;
++#endif
++ } while ((temp & CMD_SEND) && timeout--);
++
++ if (!timeout)
++ printk(KERN_ERR "timeout waiting for write to complete\n");
++
++ mutex_unlock(&car_mutex);
++}
++
++EXPORT_SYMBOL_GPL(mpc5121_ac97_read);
++EXPORT_SYMBOL_GPL(mpc5121_ac97_write);
++void mpc5121_ac97_reset(struct snd_ac97 *ac97)
++{
++ /* Initialize necessary registers of codec */
++ mpc5121_ac97_write(ac97, 0, 0x0000);
++
++ /* master channels: No attenuation */
++ mpc5121_ac97_write(ac97, 2, 0x1f1f);
++ mpc5121_ac97_write(ac97, 0x18, 0x0000);
++ mpc5121_ac97_write(ac97, 0x2a, 0x01); /* unlock VAR */
++ mpc5121_ac97_write(ac97, 0x2c, 0xbb80); /* 48KH */
++
++ mpc5121_ac97_write(ac97, 0x1c, 0x0); /*R/L 22.5dB gain*/
++ mpc5121_ac97_write(ac97, 0x1e, 0x0); /*R/L 22.5dB gain2*/
++ mpc5121_ac97_write(ac97, 0x1a, 0x0); /* Capture MIC */
++}
++EXPORT_SYMBOL_GPL(mpc5121_ac97_reset);
++
++struct snd_ac97_bus_ops soc_ac97_ops = {
++ .read = mpc5121_ac97_read,
++ .write = mpc5121_ac97_write,
++};
++EXPORT_SYMBOL_GPL(soc_ac97_ops);
+diff -Naur linux-2.6.29/sound/soc/fsl/mpc5121_ads.c linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_ads.c
+--- linux-2.6.29/sound/soc/fsl/mpc5121_ads.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_ads.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,403 @@
++/*
++ * Freescale MPC5121ADS SoC Fabric driver
++ *
++ * Copyright 2008 Freescale Semiconductor Inc.
++ * Author: John Rigby jrigby@freescale.com
++ *
++ * Originally based on mpc8610_hpcd.c:
++ * Freescale MPC8610HPCD ALSA SoC Fabric driver
++ * Author: Timur Tabi <timur@freescale.com>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without
++ * any warranty of any kind, whether express or implied.
++ */
++
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <sound/soc.h>
++#include <sound/soc-dai.h>
++
++#include <asm/of_device.h>
++#include <asm/of_platform.h>
++#include <asm/mpc52xx_psc.h>
++
++#include "../codecs/ac97.h"
++#include "mpc5121_psc_info.h"
++#include "mpc5121_pcm.h"
++
++struct mpc52xx_psc *psc_reg_priv;
++
++
++/**
++ * mpc5121_ads_startup: program the board with various hardware parameters
++ *
++ * This function takes board-specific information, like clock frequencies
++ * and serial data formats, and passes that information to the codec and
++ * transport drivers.
++ */
++static int mpc5121_ads_startup(struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
++ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
++ struct mpc5121_ads_data *machine_data = rtd->socdev->dev->platform_data;
++ int ret = 0;
++
++ /* Tell the CPU driver what the serial protocol is. */
++ if (cpu_dai->ops.set_fmt) {
++ ret = cpu_dai->ops.set_fmt(cpu_dai,
++ machine_data->dai_format);
++ if (ret < 0) {
++ dev_err(substream->pcm->card->dev,
++ "could not set CPU driver audio format\n");
++ return ret;
++ }
++ }
++
++ /* Tell the codec driver what the serial protocol is. */
++ if (codec_dai->ops.set_fmt) {
++ ret = codec_dai->ops.set_fmt(codec_dai,
++ machine_data->dai_format);
++ if (ret < 0) {
++ dev_err(substream->pcm->card->dev,
++ "could not set codec driver audio format\n");
++ return ret;
++ }
++ }
++
++ /*
++ * Tell the CPU driver what the clock frequency is, and whether it's a
++ * slave or master.
++ */
++ if (cpu_dai->ops.set_sysclk) {
++ ret = cpu_dai->ops.set_sysclk(cpu_dai, 0,
++ machine_data->clk_frequency,
++ machine_data->
++ cpu_clk_direction);
++ if (ret < 0) {
++ dev_err(substream->pcm->card->dev,
++ "could not set CPU driver clock parameters\n");
++ return ret;
++ }
++ }
++
++ /*
++ * Tell the codec driver what the MCLK frequency is, and whether it's
++ * a slave or master.
++ */
++ if (codec_dai->ops.set_sysclk) {
++ ret = codec_dai->ops.set_sysclk(codec_dai, 0,
++ machine_data->clk_frequency,
++ machine_data->
++ codec_clk_direction);
++ if (ret < 0) {
++ dev_err(substream->pcm->card->dev,
++ "could not set codec driver clock params\n");
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++/**
++ * mpc5121_ads_ops: ASoC fabric driver operations
++ */
++static struct snd_soc_ops mpc5121_ads_ops = {
++ .startup = mpc5121_ads_startup,
++};
++
++/**
++ * mpc5121_ads_machine: ASoC machine data
++ */
++static struct snd_soc_card mpc5121_ads_machine = {
++ .name = "MPC5121 ADS",
++ .num_links = 1,
++};
++
++/**
++ * mpc5121_ads_probe: OF probe function for the fabric driver
++ *
++ * This function gets called when fsl,mpc5121-psc-ac97 node
++ * is found in the device tree.
++ */
++static int mpc5121_ads_probe(struct of_device *ofdev,
++ const struct of_device_id *match)
++{
++ struct device_node *np = ofdev->node;
++ struct device_node *codec_np = NULL;
++ const char *sprop;
++ const u32 *iprop;
++ struct resource res;
++ struct platform_device *sound_device = NULL;
++ struct mpc5121_ads_data *machine_data;
++ struct mpc5121_psc_info *psc_info;
++ struct mpc512x_dma_config dma_config;
++ int ret = -ENODEV;
++
++ machine_data = kzalloc(sizeof(struct mpc5121_ads_data), GFP_KERNEL);
++ if (!machine_data)
++ return -ENOMEM;
++
++ psc_info = &machine_data->psc_info;
++ psc_info->dev = &ofdev->dev;
++
++ /*
++ * Get the device ID
++ */
++ iprop = of_get_property(np, "cell-index", NULL);
++ if (!iprop) {
++ dev_err(&ofdev->dev, "cell-index property not found\n");
++ ret = -EINVAL;
++ goto error;
++ }
++ psc_info->id = *iprop;
++
++ /* Get the serial format and clock direction. */
++ sprop = of_get_property(np, "fsl,mode", NULL);
++ if (!sprop) {
++ dev_err(&ofdev->dev, "fsl,mode property not found\n");
++ ret = -EINVAL;
++ goto error;
++ }
++
++ /* This driver is for ADS5121 which only has AC97 */
++ if (strcasecmp(sprop, "ac97-slave")) {
++ dev_err(&ofdev->dev,
++ "unrecognized fsl,mode property \"%s\"\n", sprop);
++ ret = -EINVAL;
++ goto error;
++ }
++
++ machine_data->dai_format = SND_SOC_DAIFMT_AC97;
++ machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
++ machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
++ machine_data->clk_frequency = 24576000;
++
++ /* Read the PSC information from the device tree */
++ ret = of_address_to_resource(np, 0, &res);
++ if (ret) {
++ dev_err(&ofdev->dev, "could not obtain PSC address\n");
++ goto error;
++ }
++
++ if (!res.start) {
++ dev_err(&ofdev->dev, "invalid PSC address\n");
++ goto error;
++ }
++ psc_info->phys = res.start;
++ psc_info->psc = ioremap(psc_info->phys, res.end - res.start + 1);
++ psc_reg_priv = psc_info->psc;
++ if (!psc_info->psc) {
++ dev_err(&ofdev->dev, "could not map PSC address %x\n",
++ psc_info->phys);
++ ret = -EINVAL;
++ goto error;
++ }
++
++ /* Get the IRQ of the PSC */
++ psc_info->irq = irq_of_parse_and_map(np, 0);
++ if (!psc_info->irq) {
++ dev_err(&ofdev->dev, "could not get PSC IRQ\n");
++ ret = -EINVAL;
++ goto error;
++ }
++
++#define PSC_DMA_GRAN 64
++ /*
++ * FIXME put this in the device tree
++ *
++ * DMA channels are dedicated:
++ * rx = psc number
++ * tx = psc number + 12.
++ *
++ * DMA granularity is PSC_DMA_GRAN bytes
++ *
++ * PSC FIFO data register are at
++ * rx offset is 0xfc
++ * tx offset is 0xbc
++ */
++ dma_config.rx_dma_ch_nr = psc_info->id;
++ dma_config.tx_dma_ch_nr = psc_info->id + 12;
++ psc_info->rx_dma_gran = PSC_DMA_GRAN;
++ psc_info->tx_dma_gran = PSC_DMA_GRAN;
++ dma_config.rx_dma_gran = PSC_DMA_GRAN;
++ dma_config.tx_dma_gran = PSC_DMA_GRAN;
++ dma_config.rx_dev_addr = psc_info->phys + 0xfc;
++ dma_config.tx_dev_addr = psc_info->phys + 0xbc;
++ if (!mpc512x_dma_configure(&dma_config)) {
++ dev_err(&ofdev->dev, "could not configure DMA device\n");
++ ret = -EBUSY;
++ goto error;
++ }
++
++ /*
++ * Initialize our DAI data structure.
++ */
++ machine_data->dai.name = "AC97";
++ machine_data->dai.stream_name = "AC97";
++ /*
++ * Because what bytes the psc driver
++ * supports, force the ac97 driver to only
++ * support 32 bit big endian data
++ */
++ ac97_dai.playback.formats = SNDRV_PCM_FMTBIT_S32_BE;
++ ac97_dai.capture.formats = SNDRV_PCM_FMTBIT_S32_BE;
++ /*
++ * Add 16KHz to ac97 rates
++ */
++ ac97_dai.playback.rates |= SNDRV_PCM_RATE_16000;
++ ac97_dai.capture.rates |= SNDRV_PCM_RATE_16000;
++
++ machine_data->dai.codec_dai = &ac97_dai;
++
++ machine_data->dai.cpu_dai = mpc5121_psc_create_dai(psc_info);
++ machine_data->dai.ops = &mpc5121_ads_ops;
++
++ mpc5121_ads_machine.dai_link = &machine_data->dai;
++
++ /* Allocate a new audio platform device structure */
++ sound_device = platform_device_alloc("soc-audio", -1);
++ if (!sound_device) {
++ dev_err(&ofdev->dev, "platform device allocation failed\n");
++ ret = -ENOMEM;
++ goto error;
++ }
++ machine_data->sound_devdata.card = &mpc5121_ads_machine;
++ machine_data->sound_devdata.card->platform = &mpc512x_soc_platform;
++
++ machine_data->sound_devdata.codec_dev = &soc_codec_dev_ac97;
++ machine_data->sound_devdata.codec_data = NULL;
++ sound_device->dev.platform_data = machine_data;
++
++ /* Set the platform device and ASoC device to point to each other */
++ platform_set_drvdata(sound_device, &machine_data->sound_devdata);
++ machine_data->sound_devdata.dev = &sound_device->dev;
++ /* Initialize PSC controller and codec */
++ mpc5121_psc_init(&ofdev->dev, machine_data->dai.cpu_dai);
++ ret = platform_device_add(sound_device);
++ if (ret) {
++ dev_err(&ofdev->dev, "platform device add failed\n");
++ goto error;
++ }
++
++ dev_set_drvdata(&ofdev->dev, sound_device);
++ if (machine_data->dai_format == SND_SOC_DAIFMT_AC97)
++ mpc5121_ac97_reset(NULL);
++
++ return 0;
++
++error:
++ of_node_put(codec_np);
++
++ if (sound_device)
++ platform_device_unregister(sound_device);
++
++ if (machine_data->dai.cpu_dai)
++ mpc5121_psc_destroy_dai(machine_data->dai.cpu_dai);
++
++ if (psc_info->psc)
++ iounmap(psc_info->psc);
++
++ if (psc_info->irq)
++ irq_dispose_mapping(psc_info->irq);
++
++ kfree(machine_data);
++
++ return ret;
++}
++
++/**
++ * mpc5121_ads_remove: remove the OF device
++ *
++ * This function is called when the OF device is removed.
++ */
++static int mpc5121_ads_remove(struct of_device *ofdev)
++{
++ struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev);
++ struct mpc5121_ads_data *machine_data =
++ sound_device->dev.platform_data;
++
++ platform_device_unregister(sound_device);
++
++ if (machine_data->dai.cpu_dai)
++ mpc5121_psc_destroy_dai(machine_data->dai.cpu_dai);
++
++ if (machine_data->psc_info.psc)
++ iounmap(machine_data->psc_info.psc);
++
++ kfree(machine_data);
++ sound_device->dev.platform_data = NULL;
++
++ dev_set_drvdata(&ofdev->dev, NULL);
++
++ return 0;
++}
++
++static struct of_device_id mpc5121_ads_match[] = {
++ {
++#if defined(CONFIG_PPC_MPC5125)
++ .compatible = "fsl,mpc5125-psc-ac97",
++#else
++ .compatible = "fsl,mpc5121-psc-ac97",
++#endif
++ },
++ {}
++};
++
++MODULE_DEVICE_TABLE(of, mpc5121_ads_match);
++
++static struct of_platform_driver mpc5121_ads_of_driver = {
++ .owner = THIS_MODULE,
++#if defined(CONFIG_PPC_MPC5125)
++ .name = "mpc5125_ads",
++#else
++ .name = "mpc5121_ads",
++#endif
++ .match_table = mpc5121_ads_match,
++ .probe = mpc5121_ads_probe,
++ .remove = mpc5121_ads_remove,
++};
++
++/**
++ * mpc5121_ads_init: fabric driver initialization.
++ *
++ * This function is called when this module is loaded.
++ */
++static int __init mpc5121_ads_init(void)
++{
++ int ret;
++
++ printk(KERN_INFO "Freescale MPC5121 ADS ALSA SoC fabric driver\n");
++ snd_soc_register_platform(&mpc512x_soc_platform);
++ snd_soc_register_dai(&ac97_dai);
++
++ ret = of_register_platform_driver(&mpc5121_ads_of_driver);
++
++ if (ret)
++ printk(KERN_ERR
++ "mpc5121-ads: failed to register platform driver\n");
++
++ return ret;
++}
++
++/**
++ * mpc5121_ads_exit: fabric driver exit
++ *
++ * This function is called when this driver is unloaded.
++ */
++static void __exit mpc5121_ads_exit(void)
++{
++ snd_soc_unregister_platform(&mpc512x_soc_platform);
++ snd_soc_unregister_dai(&ac97_dai);
++
++ of_unregister_platform_driver(&mpc5121_ads_of_driver);
++}
++
++module_init(mpc5121_ads_init);
++module_exit(mpc5121_ads_exit);
++
++MODULE_AUTHOR("John Rigby <jrigby@freescale.com>");
++MODULE_DESCRIPTION("Freescale MPC5121 ADS ALSA SoC fabric driver");
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.29/sound/soc/fsl/mpc5121_i2s.c linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_i2s.c
+--- linux-2.6.29/sound/soc/fsl/mpc5121_i2s.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_i2s.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,452 @@
++/*
++ * Freescale MPC5121ADS I2S SoC Fabric driver
++ *
++ * Copyright 2008 Freescale Semiconductor Inc.
++ * Author: John Rigby jrigby@freescale.com
++ *
++ * Based on mpc8610_hpcd.c:
++ * Freescale MPC8610HPCD ALSA SoC Fabric driver
++ * Author: Timur Tabi <timur@freescale.com>
++ *
++ * The ADS512101 board only has AC97, this driver is for a modified
++ * board that has an AD1938 I2S codec. The AD1938 is the SPI
++ * version of the AD1939 I2C codec.
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without
++ * any warranty of any kind, whether express or implied.
++ */
++
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <sound/soc.h>
++
++#include <asm/of_device.h>
++#include <asm/of_platform.h>
++
++#include "../codecs/ad1939.h"
++#include "mpc5121_psc_info.h"
++#include "mpc5121_pcm.h"
++
++/* setup for AD1939 codec in master mode */
++struct ad1939_setup_data mpc5121_ads_ad1939_master_setup = {
++ .dev_address = 4,
++ .pll_src = AD1939_PLL_SRC_MCLK,
++ .dac_adc_clksrc =
++ AD1939_CLKSRC_DAC_PLL |
++ AD1939_CLKSRC_ADC_PLL |
++ AD1939_CLKSRC_ENABLE_ONCHIP_VREF |
++ AD1939_BCLKSRC_DAC_PLL |
++ AD1939_BCLKSRC_ADC_EXT,
++ .mclk_xo = AD1939_MCLKXO_MCLKXI,
++ .drvflags =
++ AD1939_DRV_ADCDAC_COMMON_BCK |
++ AD1939_DRV_ADCDAC_COMMON_LRCK |
++ AD1939_DRV_ADC_LRCK_MASTER |
++ AD1939_DRV_ADC_BCK_MASTER,
++ .mixpairs = 0,
++};
++
++/* setup for AD1939 codec in slave mode */
++struct ad1939_setup_data mpc5121_ads_ad1939_slave_setup = {
++ .dev_address = 4,
++ .pll_src = AD1939_PLL_SRC_DACLRCK,
++ .dac_adc_clksrc =
++ AD1939_CLKSRC_DAC_PLL |
++ AD1939_CLKSRC_ADC_PLL |
++ AD1939_CLKSRC_ENABLE_ONCHIP_VREF |
++ AD1939_BCLKSRC_DAC_EXT |
++ AD1939_BCLKSRC_ADC_EXT,
++ .mclk_xo = AD1939_MCLKXO_OFF,
++ .drvflags = 0,
++ .mixpairs = 0,
++};
++
++struct ad1939_setup_data *codec_data;
++
++/**
++ * mpc5121_ads_startup: program the board with various hardware parameters
++ *
++ * This function takes board-specific information, like clock frequencies
++ * and serial data formats, and passes that information to the codec and
++ * transport drivers.
++ */
++static int mpc5121_ads_startup(struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
++ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
++ struct mpc5121_ads_data *machine_data = rtd->socdev->dev->platform_data;
++ int ret = 0;
++
++ /* Tell the CPU driver what the serial protocol is. */
++ if (cpu_dai->dai_ops.set_fmt) {
++ ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
++ machine_data->dai_format);
++ if (ret < 0) {
++ dev_err(substream->pcm->card->dev,
++ "could not set CPU driver audio format\n");
++ return ret;
++ }
++ }
++
++ /* Tell the codec driver what the serial protocol is. */
++ if (codec_dai->dai_ops.set_fmt) {
++ ret = codec_dai->dai_ops.set_fmt(codec_dai,
++ machine_data->dai_format);
++ if (ret < 0) {
++ dev_err(substream->pcm->card->dev,
++ "could not set codec driver audio format\n");
++ return ret;
++ }
++ }
++
++ /*
++ * Tell the CPU driver what the clock frequency is, and whether it's a
++ * slave or master.
++ */
++ if (cpu_dai->dai_ops.set_sysclk) {
++ ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, 0,
++ machine_data->clk_frequency,
++ machine_data->
++ cpu_clk_direction);
++ if (ret < 0) {
++ dev_err(substream->pcm->card->dev,
++ "could not set CPU driver clock parameters\n");
++ return ret;
++ }
++ }
++
++ /*
++ * Tell the codec driver what the MCLK frequency is, and whether it's
++ * a slave or master.
++ */
++ if (codec_dai->dai_ops.set_sysclk) {
++ ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0,
++ machine_data->clk_frequency,
++ machine_data->
++ codec_clk_direction);
++ if (ret < 0) {
++ dev_err(substream->pcm->card->dev,
++ "could not set codec driver clock params\n");
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++/**
++ * mpc5121_ads_ops: ASoC fabric driver operations
++ */
++static struct snd_soc_ops mpc5121_ads_ops = {
++ .startup = mpc5121_ads_startup,
++};
++
++/**
++ * mpc5121_ads_machine: ASoC machine data
++ */
++static struct snd_soc_machine mpc5121_ads_machine = {
++ .name = "MPC5121 ADS",
++ .num_links = 1,
++};
++
++/**
++ * mpc5121_ads_probe: OF probe function for the fabric driver
++ *
++ * This function gets called when fsl,mpc5121-psc-i2s node
++ * is found in the device tree.
++ */
++static int mpc5121_ads_probe(struct of_device *ofdev,
++ const struct of_device_id *match)
++{
++ struct device_node *np = ofdev->node;
++ struct device_node *codec_np = NULL;
++ const phandle *codec_ph;
++ const char *sprop;
++ const u32 *iprop;
++ struct resource res;
++ struct platform_device *sound_device = NULL;
++ struct mpc5121_ads_data *machine_data;
++ struct mpc5121_psc_info *psc_info;
++ struct mpc512x_dma_config dma_config;
++ int ret = -ENODEV;
++
++ machine_data = kzalloc(sizeof(struct mpc5121_ads_data), GFP_KERNEL);
++ if (!machine_data)
++ return -ENOMEM;
++
++ psc_info = &machine_data->psc_info;
++ psc_info->dev = &ofdev->dev;
++
++ /*
++ * We are only interested in PSCs with a codec phandle.
++ */
++ codec_ph = of_get_property(np, "codec-handle", NULL);
++ if (!codec_ph)
++ goto error;
++
++ codec_np = of_find_node_by_phandle(*codec_ph);
++ if (!codec_np)
++ goto error;
++
++ /*
++ * The MPC5121 ADS only knows about the AD1938 codec.
++ */
++ if (!of_device_is_compatible(codec_np, "ad,ad1938"))
++ goto error;
++ /*
++ * Get the device ID
++ */
++ iprop = of_get_property(np, "cell-index", NULL);
++ if (!iprop) {
++ dev_err(&ofdev->dev, "cell-index property not found\n");
++ ret = -EINVAL;
++ goto error;
++ }
++ psc_info->id = *iprop;
++
++ /* Get the serial format and clock direction. */
++ sprop = of_get_property(np, "fsl,mode", NULL);
++ if (!sprop) {
++ dev_err(&ofdev->dev, "fsl,mode property not found\n");
++ ret = -EINVAL;
++ goto error;
++ }
++
++ if (strcasecmp(sprop, "i2s-slave") == 0) {
++ machine_data->dai_format
++ = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM;
++ machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
++ machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
++ codec_data = &mpc5121_ads_ad1939_master_setup;
++
++ /*
++ * In i2s-slave mode, the codec has its own clock source, so we
++ * need to get the frequency from the device tree and pass it to
++ * the codec driver.
++ */
++ iprop = of_get_property(codec_np, "clock-frequency", NULL);
++ if (!iprop || !*iprop) {
++ dev_err(&ofdev->dev, "codec clock-frequency property "
++ "is missing or invalid\n");
++ ret = -EINVAL;
++ goto error;
++ }
++ machine_data->clk_frequency = *iprop;
++ } else if (strcasecmp(sprop, "i2s-master") == 0) {
++ machine_data->dai_format
++ = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
++ machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
++ machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
++ codec_data = &mpc5121_ads_ad1939_slave_setup;
++ machine_data->clk_frequency = 1; /* hack */
++ } else {
++ dev_err(&ofdev->dev,
++ "unrecognized fsl,mode property \"%s\"\n", sprop);
++ ret = -EINVAL;
++ goto error;
++ }
++
++ /* Read the PSC information from the device tree */
++ ret = of_address_to_resource(np, 0, &res);
++ if (ret) {
++ dev_err(&ofdev->dev, "could not obtain PSC address\n");
++ goto error;
++ }
++ if (!res.start) {
++ dev_err(&ofdev->dev, "invalid PSC address\n");
++ goto error;
++ }
++
++ psc_info->phys = res.start;
++ psc_info->psc = ioremap(psc_info->phys, res.end - res.start + 1);
++ if (!psc_info->psc) {
++ dev_err(&ofdev->dev, "could not map PSC address %x\n",
++ psc_info->phys);
++ ret = -EINVAL;
++ goto error;
++ }
++
++ /* Get the IRQ of the PSC */
++ psc_info->irq = irq_of_parse_and_map(np, 0);
++ if (!psc_info->irq) {
++ dev_err(&ofdev->dev, "could not get PSC IRQ\n");
++ ret = -EINVAL;
++ goto error;
++ }
++
++#define PSC_DMA_GRAN 64
++ /*
++ * FIXME put this in the device tree
++ *
++ * DMA channels are dedicated:
++ * rx = psc number
++ * tx = psc number + 12.
++ *
++ * DMA granularity is PSC_DMA_GRAN bytes
++ *
++ * PSC FIFO data register are at
++ * rx offset is 0xfc
++ * tx offset is 0xbc
++ */
++ dma_config.rx_dma_ch_nr = psc_info->id;
++ dma_config.tx_dma_ch_nr = psc_info->id + 12;
++ psc_info->rx_dma_gran = PSC_DMA_GRAN;
++ psc_info->tx_dma_gran = PSC_DMA_GRAN;
++ dma_config.rx_dma_gran = PSC_DMA_GRAN;
++ dma_config.tx_dma_gran = PSC_DMA_GRAN;
++ dma_config.rx_dev_addr = psc_info->phys + 0xfc;
++ dma_config.tx_dev_addr = psc_info->phys + 0xbc;
++ if (!mpc512x_dma_configure(&dma_config)) {
++ dev_err(&ofdev->dev, "could not configure DMA device\n");
++ ret = -EBUSY;
++ goto error;
++ }
++
++ /*
++ * Initialize our DAI data structure. We should probably get this
++ * information from the device tree.
++ */
++ machine_data->dai.name = "AD1939";
++ machine_data->dai.stream_name = "AD1939";
++
++ machine_data->dai.cpu_dai = mpc5121_psc_create_dai(psc_info);
++ machine_data->dai.codec_dai = &ad1939_dai;
++ machine_data->dai.ops = &mpc5121_ads_ops;
++
++ mpc5121_ads_machine.dai_link = &machine_data->dai;
++
++ /* Allocate a new audio platform device structure */
++ sound_device = platform_device_alloc("soc-audio", -1);
++ if (!sound_device) {
++ dev_err(&ofdev->dev, "platform device allocation failed\n");
++ ret = -ENOMEM;
++ goto error;
++ }
++
++ machine_data->sound_devdata.platform = &mpc512x_soc_platform;
++ machine_data->sound_devdata.machine = &mpc5121_ads_machine;
++ machine_data->sound_devdata.codec_dev = &soc_codec_dev_ad1939;
++ machine_data->sound_devdata.codec_data = codec_data;
++
++ sound_device->dev.platform_data = machine_data;
++
++ /* Set the platform device and ASoC device to point to each other */
++ platform_set_drvdata(sound_device, &machine_data->sound_devdata);
++ machine_data->sound_devdata.dev = &sound_device->dev;
++
++ /* Initialize PSC controller and codec */
++ mpc5121_psc_init(&ofdev->dev, machine_data->dai.cpu_dai);
++ ret = platform_device_add(sound_device);
++ if (ret) {
++ dev_err(&ofdev->dev, "platform device add failed\n");
++ goto error;
++ }
++
++ dev_set_drvdata(&ofdev->dev, sound_device);
++ return 0;
++
++error:
++ of_node_put(codec_np);
++
++ if (sound_device)
++ platform_device_unregister(sound_device);
++
++ if (machine_data->dai.cpu_dai)
++ mpc5121_psc_destroy_dai(machine_data->dai.cpu_dai);
++
++ if (psc_info->psc)
++ iounmap(psc_info->psc);
++
++ if (psc_info->irq)
++ irq_dispose_mapping(psc_info->irq);
++
++ kfree(machine_data);
++
++ return ret;
++}
++
++/**
++ * mpc5121_ads_remove: remove the OF device
++ *
++ * This function is called when the OF device is removed.
++ */
++static int mpc5121_ads_remove(struct of_device *ofdev)
++{
++ struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev);
++ struct mpc5121_ads_data *machine_data =
++ sound_device->dev.platform_data;
++
++ platform_device_unregister(sound_device);
++
++ if (machine_data->dai.cpu_dai)
++ mpc5121_psc_destroy_dai(machine_data->dai.cpu_dai);
++
++ if (machine_data->psc_info.psc)
++ iounmap(machine_data->psc_info.psc);
++
++ kfree(machine_data);
++ sound_device->dev.platform_data = NULL;
++
++ dev_set_drvdata(&ofdev->dev, NULL);
++
++ return 0;
++}
++
++static struct of_device_id mpc5121_ads_match[] = {
++ {
++ .compatible = "fsl,mpc5121-psc-i2s",
++ },
++ {
++ .compatible = "mpc512x-psc-i2s",
++ },
++ {}
++};
++
++MODULE_DEVICE_TABLE(of, mpc5121_ads_match);
++
++static struct of_platform_driver mpc5121_ads_of_driver = {
++ .owner = THIS_MODULE,
++ .name = "mpc5121_ads",
++ .match_table = mpc5121_ads_match,
++ .probe = mpc5121_ads_probe,
++ .remove = mpc5121_ads_remove,
++};
++
++/**
++ * mpc5121_ads_init: fabric driver initialization.
++ *
++ * This function is called when this module is loaded.
++ */
++static int __init mpc5121_ads_init(void)
++{
++ int ret;
++
++ printk(KERN_INFO "Freescale MPC5121 ADS ALSA SoC I2S fabric driver\n");
++
++ ret = of_register_platform_driver(&mpc5121_ads_of_driver);
++
++ if (ret)
++ printk(KERN_ERR
++ "mpc5121-ads: failed to register platform driver\n");
++
++ return ret;
++}
++
++/**
++ * mpc5121_ads_exit: fabric driver exit
++ *
++ * This function is called when this driver is unloaded.
++ */
++static void __exit mpc5121_ads_exit(void)
++{
++ of_unregister_platform_driver(&mpc5121_ads_of_driver);
++}
++
++module_init(mpc5121_ads_init);
++module_exit(mpc5121_ads_exit);
++
++MODULE_AUTHOR("John Rigby <jrigby@freescale.com>");
++MODULE_DESCRIPTION("Freescale MPC5121 ADS ALSA SoC fabric driver");
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.29/sound/soc/fsl/mpc5121_pcm.c linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_pcm.c
+--- linux-2.6.29/sound/soc/fsl/mpc5121_pcm.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_pcm.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,471 @@
++/*
++ * Freescale MPC5121 ALSA SoC PCM driver
++ * Copyright 2007,2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Author: John Rigby <jrigby@freescale.com>
++ *
++ *
++ * Originally copied from sound/mpc5121/mpc5121-pcm.c
++ * Freescale AC97 device driver for CPU MPC5121
++ * Author: Hongjun Chen <hong-jun.chen@freescale.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/delay.h>
++
++#include <sound/driver.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/soc-dai.h>
++
++#include <asm/dma.h>
++#include <asm/fsldma.h>
++#include <asm/mpc52xx_psc.h>
++
++#include "mpc5121_pcm.h"
++#include "mpc5121_psc_info.h"
++
++#define BPF 4 /* bytes per frame */
++#define SLOTS 2
++#define SAMPLESIZE (BPF*SLOTS)
++
++#define FPP (4096 / 2) //(4096 / 2) /* frames per period */
++#define PERIODS_MAX 8
++#define PERIODSIZE (SAMPLESIZE*FPP)
++#define BUFSIZE (PERIODSIZE*PERIODS_MAX)
++
++struct mpc512x_dma_config pcm_config;
++
++/*
++ * Support all these formats, actual supported format will
++ * depend on what the soc and codec driver support.
++ */
++#define MPC5121_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
++ SNDRV_PCM_FMTBIT_U8 | \
++ SNDRV_PCM_FMTBIT_S16_LE | \
++ SNDRV_PCM_FMTBIT_S16_BE | \
++ SNDRV_PCM_FMTBIT_U16_LE | \
++ SNDRV_PCM_FMTBIT_U16_BE | \
++ SNDRV_PCM_FMTBIT_S24_LE | \
++ SNDRV_PCM_FMTBIT_S24_BE | \
++ SNDRV_PCM_FMTBIT_U24_LE | \
++ SNDRV_PCM_FMTBIT_U24_BE | \
++ SNDRV_PCM_FMTBIT_S32_LE | \
++ SNDRV_PCM_FMTBIT_S32_BE | \
++ SNDRV_PCM_FMTBIT_U32_LE | \
++ SNDRV_PCM_FMTBIT_U32_BE)
++
++static const struct snd_pcm_hardware mpc512x_pcm_hardware = {
++ //.info = SNDRV_PCM_INFO_INTERLEAVED,
++ .info = SNDRV_PCM_INFO_INTERLEAVED |
++ SNDRV_PCM_INFO_MMAP |
++ SNDRV_PCM_INFO_MMAP_VALID,
++ .formats = MPC5121_PCM_FORMATS,
++ .rates = SNDRV_PCM_RATE_8000_48000,
++ .rate_min = 8000,
++ .rate_max = 48000,
++ .period_bytes_min = (FPP * SAMPLESIZE * 1),
++ .period_bytes_max = (FPP * SAMPLESIZE * PERIODS_MAX),
++ .periods_min = 1,
++ .periods_max = PERIODS_MAX,
++ .buffer_bytes_max = (FPP * SAMPLESIZE * PERIODS_MAX),
++ .fifo_size = 0,
++};
++
++struct mpc512x_runtime_data {
++ int dma_ch;
++ dma_addr_t dev_addr;
++ struct fsl_dma_requestbuf dma_desc_array[PERIODS_MAX];
++ dma_addr_t dma_desc_array_phys;
++ int current_period;
++ int stopping;
++};
++
++static int mpc512x_pcm_close(struct snd_pcm_substream *substream);
++static int period_len;
++static int mpc512x_pcm_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct mpc512x_runtime_data *rtd = runtime->private_data;
++ size_t totsize = params_buffer_bytes(params);
++ size_t period = params_period_bytes(params);
++ struct fsl_dma_requestbuf *dma_desc;
++ dma_addr_t dma_buff_phys;
++
++ period_len = period;
++
++ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
++ runtime->dma_bytes = totsize;
++
++ dma_desc = rtd->dma_desc_array;
++ dma_buff_phys = runtime->dma_addr;
++
++ do {
++ if (period > totsize)
++ period = totsize;
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ dma_desc->src = dma_buff_phys;
++ dma_desc->dest = rtd->dev_addr;
++ dma_desc->minor_loop = pcm_config.tx_dma_gran /
++ sizeof(u32);
++ dma_desc->soff = sizeof(u32);
++ dma_desc->doff = 0;
++ } else {
++ dma_desc->src = rtd->dev_addr;
++ dma_desc->dest = dma_buff_phys;
++ dma_desc->minor_loop = pcm_config.rx_dma_gran /
++ sizeof(u32);
++ dma_desc->soff = 0;
++ dma_desc->doff = sizeof(u32);
++ }
++ dma_desc->len = period;
++ dma_desc++;
++ dma_buff_phys += period;
++ memset(dma_desc, 0, sizeof(*dma_desc));
++ } while ((totsize -= period) > 0);
++
++ return 0;
++}
++
++static int mpc512x_pcm_hw_free(struct snd_pcm_substream *substream)
++{
++ snd_pcm_set_runtime_buffer(substream, NULL);
++ return 0;
++}
++
++static int mpc512x_pcm_prepare(struct snd_pcm_substream *substream)
++{
++ struct mpc512x_runtime_data *rtd = substream->runtime->private_data;
++ rtd->current_period = 0;
++ return 0;
++}
++
++static int mpc512x_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
++{
++ struct mpc512x_runtime_data *rtd = substream->runtime->private_data;
++ int ret = 0;
++ int dmaerr;
++
++ switch (cmd) {
++ case SNDRV_PCM_TRIGGER_STOP:
++ rtd->stopping++;
++ break;
++
++ case SNDRV_PCM_TRIGGER_START:
++ if (rtd->stopping) {
++ rtd->stopping = 0;
++ } else {
++ dmaerr = fsl_dma_config(rtd->dma_ch,
++ &rtd->dma_desc_array[rtd->current_period], 1);
++ if (dmaerr) {
++ printk(KERN_ERR "unexpected error in "
++ "mpc512x_pcm_trigger %d\n", -dmaerr);
++ } else {
++ fsl_dma_enable(rtd->dma_ch);
++ }
++ }
++ break;
++ case SNDRV_PCM_TRIGGER_SUSPEND:
++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++ case SNDRV_PCM_TRIGGER_RESUME:
++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++ default:
++ ret = -EINVAL;
++ }
++ return ret;
++}
++
++static void mpc512x_pcm_dma_callback(void *dev_id, int err_status)
++{
++ struct snd_pcm_substream *substream = dev_id;
++ struct mpc512x_runtime_data *rtd = substream->runtime->private_data;
++ int dmaerr;
++
++ if (!err_status) {
++ if (rtd->stopping) {
++ rtd->stopping = 0;
++ return;
++ }
++
++ rtd->current_period++;
++ rtd->current_period %= substream->runtime->periods;
++
++ dmaerr = fsl_dma_config(rtd->dma_ch,
++ &rtd->dma_desc_array[rtd->current_period], 1);
++ if (dmaerr)
++ printk(KERN_ERR "unexpected error in "
++ "mpc512x_pcm_dma_callback %d\n", -dmaerr);
++ else
++ fsl_dma_enable(rtd->dma_ch);
++
++ snd_pcm_period_elapsed(substream);
++ } else {
++ printk(KERN_ERR
++ "%s: DMA error on channel %d (Error Status=%#x)\n",
++ __FUNCTION__, rtd->dma_ch, err_status);
++ snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
++ }
++}
++
++static snd_pcm_uframes_t mpc512x_pcm_pointer(struct snd_pcm_substream
++ *substream)
++{
++ struct mpc512x_runtime_data *rtd = substream->runtime->private_data;
++
++ return rtd->current_period * substream->runtime->period_size;
++}
++
++static int mpc512x_pcm_open(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct mpc512x_runtime_data *rtd;
++ int dma_ch_nr;
++ int ret;
++
++ runtime->hw = mpc512x_pcm_hardware;
++
++ ret = snd_pcm_hw_constraint_integer(runtime,
++ SNDRV_PCM_HW_PARAM_PERIODS);
++ ret = -ENOMEM;
++
++ rtd = kzalloc(sizeof(*rtd), GFP_KERNEL);
++ if (!rtd)
++ goto err1;
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ rtd->dev_addr = pcm_config.tx_dev_addr;
++ dma_ch_nr = pcm_config.tx_dma_ch_nr;
++ } else {
++ rtd->dev_addr = pcm_config.rx_dev_addr;
++ dma_ch_nr = pcm_config.rx_dma_ch_nr;
++ }
++
++ /* Allocate DMA channel for this substream */
++ ret = fsl_dma_chan_request(dma_ch_nr);
++ if (ret < 0) {
++ printk(KERN_ERR
++ "Err: can't allocate DMA channel %d for PSC!\n",
++ dma_ch_nr);
++ goto err2;
++ }
++
++ rtd->dma_ch = ret;
++ fsl_dma_callback_set(rtd->dma_ch,
++ mpc512x_pcm_dma_callback, (void *)substream);
++
++ runtime->private_data = rtd;
++
++ return 0;
++
++err2:
++ kfree(rtd);
++err1:
++ return ret;
++}
++
++static int mpc512x_pcm_close(struct snd_pcm_substream *substream)
++{
++ struct mpc512x_runtime_data *rtd = substream->runtime->private_data;
++
++ if (rtd && rtd->dma_ch >= 0)
++ fsl_dma_free_chan(rtd->dma_ch);
++
++ kfree(rtd);
++ return 0;
++}
++static int mpc512x_pcm_mmap(struct snd_pcm_substream *substream,
++ struct vm_area_struct *area)
++{
++ if (!substream->ops->page)
++ return dma_mmap_coherent(substream->dma_buffer.dev.dev,
++ area,
++ substream->runtime->dma_area,
++ substream->runtime->dma_addr,
++ area->vm_end - area->vm_start);
++ return 0;
++}
++
++static struct snd_pcm_ops mpc512x_pcm_ops = {
++ .open = mpc512x_pcm_open,
++ .close = mpc512x_pcm_close,
++ .ioctl = snd_pcm_lib_ioctl,
++ .hw_params = mpc512x_pcm_hw_params,
++ .hw_free = mpc512x_pcm_hw_free,
++ .prepare = mpc512x_pcm_prepare,
++ .trigger = mpc512x_pcm_trigger,
++ .pointer = mpc512x_pcm_pointer,
++ .mmap = mpc512x_pcm_mmap,
++};
++
++static int mpc512x_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
++{
++ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
++ struct snd_dma_buffer *buf = &substream->dma_buffer;
++ size_t size = mpc512x_pcm_hardware.buffer_bytes_max;
++ buf->dev.type = SNDRV_DMA_TYPE_DEV;
++ buf->dev.dev = pcm->card->dev;
++ buf->private_data = NULL;
++ buf->area = dma_alloc_coherent(pcm->card->dev, size,
++ &buf->addr, GFP_KERNEL);
++ if (!buf->area)
++ return -ENOMEM;
++ buf->bytes = size;
++ return 0;
++}
++
++static void mpc512x_pcm_free_dma_buffers(struct snd_pcm *pcm)
++{
++ struct snd_pcm_substream *substream;
++ struct snd_dma_buffer *buf;
++ int stream;
++
++ for (stream = 0; stream < 2; stream++) {
++ substream = pcm->streams[stream].substream;
++ if (!substream)
++ continue;
++ buf = &substream->dma_buffer;
++ if (!buf || !buf->area)
++ continue;
++ dma_free_coherent(pcm->card->dev, buf->bytes,
++ buf->area, buf->addr);
++ buf->area = NULL;
++ }
++}
++
++static int mpc512x_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
++ struct snd_pcm *pcm)
++{
++ int ret = 0;
++
++ if (dai->playback.channels_min) {
++ ret =
++ mpc512x_pcm_preallocate_dma_buffer(pcm,
++ SNDRV_PCM_STREAM_PLAYBACK);
++ if (ret)
++ goto out;
++ }
++ if (dai->capture.channels_min) {
++ ret =
++ mpc512x_pcm_preallocate_dma_buffer(pcm,
++ SNDRV_PCM_STREAM_CAPTURE);
++ if (ret)
++ goto out;
++ }
++
++ ret = 0;
++
++out:
++ return ret;
++}
++
++#ifdef CONFIG_PM
++static unsigned short headphone, lineout, mono, mix1, mix2;
++static int mpc512x_pcm_suspend(struct snd_soc_dai *dai)
++{
++ struct mpc5121_psc_private *psc_private=dai->private_data;
++ struct mpc52xx_psc *psc = psc_private->psc;
++ struct mpc512x_psc_fifo *fifo;
++ fifo = (struct mpc512x_psc_fifo *)
++ (psc_private->psc + sizeof(struct mpc52xx_psc));
++
++#ifdef CONFIG_SND_SOC_MPC5121_ADS
++ if (psc_private->format == SND_SOC_DAIFMT_AC97)
++ headphone = mpc5121_ac97_read(NULL, 4);
++ lineout = mpc5121_ac97_read(NULL, 2);
++ mono = mpc5121_ac97_read(NULL, 6);
++ mix1 = mpc5121_ac97_read(NULL, 0x12);
++ mix2 = mpc5121_ac97_read(NULL, 0x18);
++#endif
++
++ /* Disable AC97 controller */
++ out_be32(&psc->sicr, 0);
++
++ /* Disable FIFO rx/tx slices, */
++ out_be32(&fifo->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
++ out_be32(&fifo->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
++
++ /* Disable clock */
++ mpc5121_psc_clkinit(psc_private, 0);
++
++ return 0;
++}
++extern void mpc5121ads_ac97_pm_restore(void);
++static int mpc512x_pcm_resume(struct snd_soc_dai *dai)
++{
++ struct mpc5121_psc_private *psc_private = dai->private_data;
++ unsigned int playback, capture;
++
++
++ mpc5121ads_ac97_pm_restore();
++
++ playback = psc_private->playback;
++ capture = psc_private->capture;
++ psc_private->playback = 0;
++ psc_private->capture = 0;
++
++ mpc5121_psc_init(NULL, dai);
++ psc_private->playback = playback;
++ psc_private->capture = capture;
++#ifdef CONFIG_SND_SOC_MPC5121_ADS
++ if (psc_private->format == SND_SOC_DAIFMT_AC97)
++ mpc5121_ac97_reset(NULL);
++ mpc5121_ac97_write(NULL, 4, headphone);
++ mpc5121_ac97_write(NULL, 4, headphone);
++ mpc5121_ac97_write(NULL, 2, lineout);
++ mpc5121_ac97_write(NULL, 2, mono);
++ mpc5121_ac97_write(NULL, 0x12, mix1);
++ mpc5121_ac97_write(NULL, 0x18, mix2);
++#else
++ (void)psc_private;
++#endif
++
++ return 0;
++}
++#else
++#define mpc512x_pcm_suspend NULL
++#define mpc512x_pcm_resume NULL
++#endif
++
++struct snd_soc_platform mpc512x_soc_platform = {
++ .name = "MPC5121-audio",
++ .pcm_ops = &mpc512x_pcm_ops,
++ .pcm_new = mpc512x_pcm_new,
++ .pcm_free = mpc512x_pcm_free_dma_buffers,
++ .suspend = mpc512x_pcm_suspend,
++ .resume = mpc512x_pcm_resume,
++};
++EXPORT_SYMBOL_GPL(mpc512x_soc_platform);
++
++/*
++ * pass config info about the PSC driver to the DMA driver
++ */
++int mpc512x_dma_configure(struct mpc512x_dma_config *config)
++{
++ static int initialized;
++
++ if (initialized)
++ return 0;
++
++ pcm_config = *config;
++ initialized = 1;
++
++ return 1;
++}
++EXPORT_SYMBOL_GPL(mpc512x_dma_configure);
++
++
++MODULE_AUTHOR("John Rigby <jrigby@freescale.com>");
++MODULE_DESCRIPTION("Freescale MPC512x ASoC PCM module");
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.29/sound/soc/fsl/mpc5121_pcm.h linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_pcm.h
+--- linux-2.6.29/sound/soc/fsl/mpc5121_pcm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_pcm.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,32 @@
++/*
++ * Freescale MPC5121 ALSA SoC PCM driver
++ *
++ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Author: John Rigby <jrigby@freescale.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ */
++
++#ifndef __MPC5121_PCM_H__
++#define __MPC5121_PCM_H__
++struct mpc512x_dma_config {
++ int rx_dma_ch_nr;
++ int tx_dma_ch_nr;
++ dma_addr_t rx_dev_addr;
++ dma_addr_t tx_dev_addr;
++ int rx_dma_gran;
++ int tx_dma_gran;
++};
++
++
++extern struct snd_soc_platform mpc512x_soc_platform;
++
++/*
++ * pass config info about the PSC driver to the DMA driver
++ */
++extern int mpc512x_dma_configure(struct mpc512x_dma_config *config);
++#endif /* __MPC5121_PCM_H__ */
+diff -Naur linux-2.6.29/sound/soc/fsl/mpc5121_psc.c linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_psc.c
+--- linux-2.6.29/sound/soc/fsl/mpc5121_psc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_psc.c 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,625 @@
++/*
++ * Freescale MPC5121 PSC ALSA SoC Digital Audio Interface (DAI) driver
++ *
++ * Copyright 2008 Freescale Semiconductor, Inc.
++ * Author: John Rigby <jrigby@freescale.com>
++ *
++ * Based on
++ * fsl_ssi.c -- Author: Timur Tabi <timur@freescale.com>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without
++ * any warranty of any kind, whether express or implied.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <linux/clk.h>
++
++#include <asm/mpc52xx_psc.h>
++#include <asm/mpc512x.h>
++
++#include <sound/driver.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/initval.h>
++#include <sound/soc.h>
++#include <sound/soc-dai.h>
++
++#include "mpc5121_psc_info.h"
++
++/*
++ * Three scenarios:
++ * AC97: PSC is slave so claim support for all speeds and let codec
++ * determine the rate.
++ * ICS Slave: PSC is slave so identical above.
++ * ICS Master: PSC is master which can do any speed
++ *
++ * So for all three modes 8000-48000 continuous is ok
++ */
++#define PSC_SAMPLE_RATES SNDRV_PCM_RATE_8000_48000
++
++/*
++ * AC97 sample width is upto 20 bits, the next unpacked size if 32.
++ * I2S works for 8, 16 and 32
++ */
++#define PSC_AC97_FORMATS SNDRV_PCM_FMTBIT_S32_BE
++#define PSC_I2S_FORMATS ( \
++ SNDRV_PCM_FMTBIT_S32_BE | \
++ SNDRV_PCM_FMTBIT_S16_BE | \
++ SNDRV_PCM_FMTBIT_S8 | \
++ 0)
++
++struct {
++ int tot;
++ int al;
++ int em;
++ int ur;
++ int or;
++ int me;
++ int update;
++} pscstats;
++
++/**
++ * mpc5121_psc_isr: PSC interrupt handler
++ *
++ * All data transfer is done via dma. This handler is just for errors.
++ *
++ * @irq: IRQ of the PSC device
++ * @dev_id: pointer to the psc_private structure for this PSC device
++ */
++static irqreturn_t mpc5121_psc_isr(int irq, void *dev_id)
++{
++ struct mpc5121_psc_private *psc_private = dev_id;
++ irqreturn_t ret = IRQ_NONE;
++ struct mpc512x_psc_fifo *fifo;
++ u32 isr;
++
++ fifo = (struct mpc512x_psc_fifo *)
++ (psc_private->psc + sizeof(struct mpc52xx_psc));
++
++ isr = in_be32(&fifo->rxisr);
++ out_be32(&fifo->rxisr, isr);
++
++ isr = in_be32(&fifo->txisr);
++ out_be32(&fifo->txisr, isr);
++
++ if (isr & MPC512x_PSC_FIFO_ALARM)
++ pscstats.al++;
++ if (isr & MPC512x_PSC_FIFO_URERR)
++ pscstats.ur++;
++ if (isr & MPC512x_PSC_FIFO_ORERR)
++ pscstats.or++;
++ if (isr & MPC512x_PSC_FIFO_MEMERROR)
++ pscstats.me++;
++ if (isr & MPC512x_PSC_FIFO_EMPTY)
++ pscstats.em++;
++
++ if (isr) {
++ pscstats.tot++;
++ pscstats.update++;
++ ret = IRQ_HANDLED;
++ }
++
++#ifdef DEBUG
++ if (pscstats.update > 10000) {
++ pscstats.update = 0;
++ printk(KERN_ERR "al %d ur %d or %d me %d em %d tot %d\n",
++ pscstats.al,
++ pscstats.ur,
++ pscstats.or,
++ pscstats.me,
++ pscstats.em,
++ pscstats.tot);
++ }
++#endif
++
++ return ret;
++}
++
++int mpc5121_psc_clkinit(struct mpc5121_psc_private *psc_private, int on)
++{
++ /* when adding master this will need to do more */
++ char clockname[256];
++ struct clk *clk;
++
++ sprintf(clockname, "psc%d_mclk", psc_private->cpu_dai.id);
++
++ clk = psc_private->clk = clk_get(NULL, clockname);
++ if (IS_ERR(psc_private->clk)) {
++ printk(KERN_ERR "%s: can't probe clock"
++ " source for PSC SOC.\n", __FUNCTION__);
++ psc_private->clk = NULL;
++ return PTR_ERR(clk);
++ }
++
++ if (on)
++ clk_enable(clk);
++ else
++ clk_disable(clk);
++
++ clk_put(clk);
++
++ return 0;
++}
++
++void mpc5121_psc_fifo_init(struct mpc5121_psc_private *psc_private)
++{
++ struct mpc512x_psc_fifo *fifo;
++ unsigned long size;
++
++ fifo = (struct mpc512x_psc_fifo *)
++ (psc_private->psc + sizeof(struct mpc52xx_psc));
++
++ out_be32(&fifo->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
++ out_be32(&fifo->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
++
++ /*
++ * Make sure that dma granularity does not
++ * exceed the fifo size.
++ */
++ size = in_be32(&fifo->rxsz) * 4;
++
++ if (size < psc_private->rx_dma_gran)
++ printk(KERN_WARNING "rx dma granularity exceeds fifo size\n");
++ out_be32(&fifo->rxalarm, size - psc_private->rx_dma_gran);
++
++ size = in_be32(&fifo->txsz) * 4;
++
++ if (size < psc_private->tx_dma_gran)
++ printk(KERN_WARNING "tx dma granularity exceeds fifo size\n");
++ out_be32(&fifo->txalarm, size - psc_private->tx_dma_gran);
++}
++
++void mpc5121_psc_fifo_enable(struct mpc5121_psc_private *psc_private)
++{
++ struct mpc512x_psc_fifo *fifo;
++
++ fifo = (struct mpc512x_psc_fifo *)
++ (psc_private->psc + sizeof(struct mpc52xx_psc));
++
++ out_be32(&fifo->rxcmd,
++ MPC512x_PSC_FIFO_ENABLE_SLICE | MPC512x_PSC_FIFO_ENABLE_DMA);
++ out_be32(&fifo->txcmd,
++ MPC512x_PSC_FIFO_ENABLE_SLICE | MPC512x_PSC_FIFO_ENABLE_DMA);
++}
++
++int mpc5121_psc_init(struct device *dev, struct snd_soc_dai *cpu_dai)
++{
++ struct mpc5121_psc_private *psc_private = cpu_dai->private_data;
++ int err;
++ /*
++ * If this is the first stream opened, then request the IRQ
++ * and initialize the PSC registers.
++ */
++ if (!psc_private->playback && !psc_private->capture) {
++ struct mpc52xx_psc __iomem *psc = psc_private->psc;
++ err = mpc5121_psc_clkinit(psc_private, 1);
++ if (err < 0) {
++ dev_err(dev, "could not initialize psc clk\n");
++ goto noclock;
++ }
++
++ /* disable */
++ out_8(&psc->command,
++ MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
++
++ mpc5121_psc_fifo_init(psc_private);
++
++ /* reset everything */
++ out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
++ out_8(&psc->command, MPC52xx_PSC_RST_RX);
++ out_8(&psc->command, MPC52xx_PSC_RST_TX);
++ out_8(&psc->command, MPC52xx_PSC_RST_ERR_STAT);
++ out_8(&psc->command, MPC52xx_PSC_RST_BRK_CHG_INT);
++ out_8(&psc->command, MPC52xx_PSC_STOP_BRK);
++
++ switch(psc_private->format) {
++ case SND_SOC_DAIFMT_AC97:
++ /*
++ * set up the psc for AC97 mode
++ */
++ out_be32(&psc->sicr,
++ 0x03000000 | /* SIM = 0011 : AC97 mode */
++ 0x00010000 | /* EnAC97 = 1 : Normal mode */
++ 0x00000100 | /* Outputs always enabled */
++ 0);
++
++ out_be32(&psc->ac97slots,
++ 0x300 << 16 | /* Enable tx timeslot 3,4 */
++ 0x300 | /* Enable rx timeslot 3,4 */
++ 0);
++
++ /*
++ * Reset external AC97 codec
++ * Some codecs go into test mode if the data or sync lines
++ * are high when the reset line goes high.
++ * Avoid that by forcing them to GPIOs and driving them
++ * low during reset.
++ */
++
++ mpc5121_pscgpio_make_gpio(cpu_dai->id, 1);
++ mpc5121_pscgpio_pin_low(cpu_dai->id, 1);
++ mpc5121_pscgpio_make_gpio(cpu_dai->id, 2);
++ mpc5121_pscgpio_pin_low(cpu_dai->id, 2);
++ mpc5121_pscgpio_make_psc(cpu_dai->id, 4);
++
++ out_8(&psc->op1, 0x02); iosync();
++ udelay(1);
++ out_8(&psc->op0, 0x02); iosync();
++ udelay(1);
++
++
++ /*
++ * Reset complete, change lines back to PSC signals.
++ */
++ mpc5121_pscgpio_make_psc(cpu_dai->id, 1);
++ mpc5121_pscgpio_make_psc(cpu_dai->id, 2);
++ mpc5121_pscgpio_make_psc(cpu_dai->id, 3);
++ break;
++ case SND_SOC_DAIFMT_I2S:
++ out_be32(&psc->sicr,
++ 0x20000000 | /* DTS = 1 : Delay 1 bit time (I2S) */
++ 0x0f000000 | /* SIM = 1111 : Codec 32 bit */
++ 0x00400000 | /* I2S = 1 : I2S */
++ 0x00200000 | /* CLKPOL = 1 : */
++ 0x00000100 | /* Outputs always enabled */
++ 0);
++ break;
++ }
++
++ /* enable the fifos */
++ mpc5121_psc_fifo_enable(psc_private);
++
++ /* enable rx and tx now */
++ out_8(&psc->command, MPC52xx_PSC_TX_ENABLE |
++ MPC52xx_PSC_RX_ENABLE);
++ }
++
++ return 0;
++noclock:
++ return err;
++}
++EXPORT_SYMBOL_GPL(mpc5121_psc_init);
++
++/**
++ * mpc5121_psc_startup: create a new substream
++ *
++ * This is the first function called when a stream is opened.
++ *
++ * If this is the first stream open, then grab the IRQ and program most of
++ * the PSC registers.
++ */
++static int mpc5121_psc_startup(struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct mpc5121_psc_private *psc_private =
++ rtd->dai->cpu_dai->private_data;
++
++ /*
++ * If this is the first stream opened, then request the IRQ
++ * and initialize the PSC registers.
++ */
++ if (!psc_private->playback && !psc_private->capture) {
++ int ret;
++ ret = request_irq(psc_private->irq, mpc5121_psc_isr,
++ IRQF_SHARED,
++ psc_private->name, psc_private);
++ if (ret < 0) {
++ dev_err(substream->pcm->card->dev,
++ "could not claim irq %u\n", psc_private->irq);
++ return ret;
++ }
++ }
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ psc_private->playback++;
++
++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
++ psc_private->capture++;
++
++ return 0;
++}
++
++/**
++ * mpc5121_psc_prepare: prepare the PSC.
++ */
++static int mpc5121_psc_prepare(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct mpc5121_psc_private *psc_private =
++ rtd->dai->cpu_dai->private_data;
++ struct mpc52xx_psc __iomem *psc = psc_private->psc;
++ int width;
++ int sicr;
++ int bclkdiv;
++ int ccr;
++
++ switch(psc_private->format) {
++ case SND_SOC_DAIFMT_AC97:
++ /* nothing to do, original init is good */
++ break;
++ case SND_SOC_DAIFMT_I2S:
++ /* reset everything */
++ out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
++ out_8(&psc->command, MPC52xx_PSC_RST_RX);
++ out_8(&psc->command, MPC52xx_PSC_RST_TX);
++ out_8(&psc->command, MPC52xx_PSC_RST_ERR_STAT);
++ out_8(&psc->command, MPC52xx_PSC_STOP_BRK);
++
++ /* format */
++ sicr = 0x20000000 | /* DTS = 1 : Delay 1 bit time (I2S) */
++ (psc_private->clk_dir == SND_SOC_CLOCK_OUT ?
++ 0x00800000 : /* GenClk = 1 : master */
++ 0x00000000)| /* GenClk = 0 : slave */
++ 0x00400000 | /* I2S = 1 : I2S */
++ 0x00200000 | /* CLKPOL = 1 : */
++ 0x00000100 | /* Outputs always enabled */
++ 0;
++
++ width = snd_pcm_format_width(runtime->format);
++ switch (width) {
++ case 8:
++ sicr |= 0x01000000;
++ break;
++ case 16:
++ sicr |= 0x02000000;
++ break;
++ case 32:
++ sicr |= 0x0f000000;
++ break;
++ }
++ out_be32(&psc->sicr, sicr);
++
++
++ /* rate based on 64 bit clks per frame */
++ bclkdiv = psc_private->clk_rate / (runtime->rate * 64) - 1;
++
++ ccr = ((64-1) << 24)
++ | ((bclkdiv & 0xff) << 16)
++ | (((bclkdiv >> 8) & 0xff) << 8);
++ out_be32(&psc->ccr, ccr);
++ out_8(&psc->ctur, (64/2)-1);
++
++ out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
++ break;
++ }
++
++ return 0;
++}
++
++/**
++ * mpc5121_psc_trigger: start and stop the DMA transfer.
++ *
++ * This function is called by ALSA to start, stop, pause, and resume the DMA
++ * transfer of data.
++ *
++ * The DMA channel is in external master start and pause mode, which
++ * means the PSC completely controls the flow of data.
++ */
++static int mpc5121_psc_trigger(struct snd_pcm_substream *substream, int cmd)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct mpc5121_psc_private *psc_private =
++ rtd->dai->cpu_dai->private_data;
++ struct mpc512x_psc_fifo *fifo;
++
++ fifo = (struct mpc512x_psc_fifo *)
++ (psc_private->psc + sizeof(struct mpc52xx_psc));
++ switch (cmd) {
++ case SNDRV_PCM_TRIGGER_START:
++ case SNDRV_PCM_TRIGGER_RESUME:
++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ out_be32(&fifo->tximr,
++ MPC512x_PSC_FIFO_MEMERROR |
++ MPC512x_PSC_FIFO_ORERR |
++ MPC512x_PSC_FIFO_URERR);
++ else
++ out_be32(&fifo->rximr,
++ MPC512x_PSC_FIFO_MEMERROR |
++ MPC512x_PSC_FIFO_ORERR |
++ MPC512x_PSC_FIFO_URERR);
++ break;
++
++ case SNDRV_PCM_TRIGGER_STOP:
++ case SNDRV_PCM_TRIGGER_SUSPEND:
++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ out_be32(&fifo->tximr, 0);
++ else
++ out_be32(&fifo->rximr, 0);
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/**
++ * mpc5121_psc_shutdown: shutdown the PSC
++ *
++ * Shutdown the PSC if there are no other substreams open.
++ */
++static void mpc5121_psc_shutdown(struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct mpc5121_psc_private *psc_private =
++ rtd->dai->cpu_dai->private_data;
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ psc_private->playback--;
++
++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
++ psc_private->capture--;
++
++ /*
++ * If this is the last active substream, disable the PSC and release
++ * the IRQ.
++ */
++ if (!psc_private->playback && !psc_private->capture) {
++ void __iomem *psc = psc_private->psc;
++
++ (void)psc;
++ printk(KERN_INFO "psc shutting down %p\n", psc);
++
++ free_irq(psc_private->irq, psc_private);
++ }
++}
++
++/**
++ * mpc5121_psc_set_sysclk: set the clock frequency and direction
++ *
++ * This function is called by the machine driver to tell us what the clock
++ * frequency and direction are.
++ *
++ * When runniing as a clock slave (SND_SOC_CLOCK_IN) then we don't care about
++ * the rate.
++ *
++ * When running as a clock master (SND_SOC_CLOCK_OUT) then we use the clock
++ * rate obtained from the clock driver via clk_get_rate.
++ *
++ * @clk_id: reserved, should be zero
++ * @freq: the frequency of the given clock ID, currently ignored
++ * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
++ */
++static int mpc5121_psc_set_sysclk(struct snd_soc_dai *mpc5121_psc_dai,
++ int clk_id, unsigned int freq, int dir)
++{
++ struct mpc5121_psc_private *psc_private =
++ container_of(mpc5121_psc_dai, struct mpc5121_psc_private, cpu_dai);
++
++ psc_private->clk_dir = dir;
++ return 0;
++}
++
++/**
++ * mpc5121_psc_set_fmt: set the serial format.
++ *
++ * This function is called by the machine driver to tell us what serial
++ * format to use.
++ *
++ * Currently AC97 and I2S are supported
++ *
++ * @format: one of SND_SOC_DAIFMT_xxx
++ */
++static int mpc5121_psc_set_fmt(struct snd_soc_dai *mpc5121_psc_dai,
++ unsigned int format)
++{
++ struct mpc5121_psc_private *psc_private =
++ container_of(mpc5121_psc_dai, struct mpc5121_psc_private, cpu_dai);
++
++ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
++ case SND_SOC_DAIFMT_AC97:
++ case SND_SOC_DAIFMT_I2S:
++ break;
++ default:
++ return -EINVAL;
++ }
++ psc_private->format = format;
++ return 0;
++}
++
++/**
++ * mpc5121_psc_dai_template: template CPU DAI for the PSC
++ */
++static struct snd_soc_dai mpc5121_psc_dai_template = {
++ .playback = {
++ /* The PSC does not support monaural audio. */
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = PSC_SAMPLE_RATES,
++ .formats = PSC_AC97_FORMATS,
++ },
++ .capture = {
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = PSC_SAMPLE_RATES,
++ .formats = PSC_AC97_FORMATS,
++ },
++ .ops = {
++ .startup = mpc5121_psc_startup,
++ .prepare = mpc5121_psc_prepare,
++ .shutdown = mpc5121_psc_shutdown,
++ .trigger = mpc5121_psc_trigger,
++ },
++ .ops = {
++ .set_sysclk = mpc5121_psc_set_sysclk,
++ .set_fmt = mpc5121_psc_set_fmt,
++ },
++};
++
++/**
++ * mpc5121_psc_create_dai: create a snd_soc_cpu_dai structure
++ *
++ * This function is called by the machine driver to create a snd_soc_cpu_dai
++ * structure. The function creates an psc_private object, which contains
++ * the snd_soc_cpu_dai. It also creates the sysfs statistics device.
++ */
++struct snd_soc_dai *mpc5121_psc_create_dai(struct mpc5121_psc_info
++ *psc_info)
++{
++ struct snd_soc_dai *mpc5121_psc_dai;
++ struct mpc5121_psc_private *psc_private;
++ struct mpc5121_ads_data *ads_data = container_of(psc_info,
++ struct mpc5121_ads_data, psc_info);
++
++ psc_private = kzalloc(sizeof(struct mpc5121_psc_private), GFP_KERNEL);
++ if (!psc_private) {
++ dev_err(psc_info->dev, "could not allocate DAI object\n");
++ return NULL;
++ }
++ memcpy(&psc_private->cpu_dai, &mpc5121_psc_dai_template,
++ sizeof(struct snd_soc_dai));
++
++ if (ads_data->dai_format == SND_SOC_DAIFMT_I2S) {
++ psc_private->cpu_dai.playback.formats = PSC_I2S_FORMATS;
++ psc_private->cpu_dai.capture.formats = PSC_I2S_FORMATS;
++ }
++
++ mpc5121_psc_dai = &psc_private->cpu_dai;
++
++ sprintf(psc_private->name, "psc%u", (u8) psc_info->id);
++ psc_private->psc = psc_info->psc;
++ psc_private->phys = psc_info->phys;
++ psc_private->irq = psc_info->irq;
++ psc_private->dev = psc_info->dev;
++ psc_private->rx_dma_gran = psc_info->rx_dma_gran;
++ psc_private->tx_dma_gran = psc_info->tx_dma_gran;
++
++ psc_private->dev->driver_data = mpc5121_psc_dai;
++ psc_private->format = ads_data->dai_format;
++
++ mpc5121_psc_dai->private_data = psc_private;
++ mpc5121_psc_dai->name = psc_private->name;
++ mpc5121_psc_dai->id = psc_info->id;
++ snd_soc_register_dai(&psc_private->cpu_dai);
++ return mpc5121_psc_dai;
++}
++EXPORT_SYMBOL_GPL(mpc5121_psc_create_dai);
++
++/**
++ * mpc5121_psc_destroy_dai: destroy the snd_soc_cpu_dai object
++ *
++ * This function undoes the operations of mpc5121_psc_create_dai()
++ */
++void mpc5121_psc_destroy_dai(struct snd_soc_dai *mpc5121_psc_dai)
++{
++ struct mpc5121_psc_private *psc_private =
++ container_of(mpc5121_psc_dai, struct mpc5121_psc_private, cpu_dai);
++ snd_soc_unregister_dai(&psc_private->cpu_dai);
++
++ kfree(psc_private);
++}
++EXPORT_SYMBOL_GPL(mpc5121_psc_destroy_dai);
++
++MODULE_AUTHOR("John Rigby <jrigby@freescale.com>");
++MODULE_DESCRIPTION("Freescale psc ASoC Driver");
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.29/sound/soc/fsl/mpc5121_psc_info.h linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_psc_info.h
+--- linux-2.6.29/sound/soc/fsl/mpc5121_psc_info.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.29-v2010041601/sound/soc/fsl/mpc5121_psc_info.h 2010-04-13 20:23:26.000000000 +0200
+@@ -0,0 +1,88 @@
++/*
++ * mpc5121_psc_info.h - ALSC PSC interface for Freescale MPC5121ADS SoC
++ *
++ * Copyright 2008 Freescale Semiconductor Inc.
++ * Author: John Rigby jrigby@freescale.com
++ *
++ * Based on fsl_ssi.h - Author Timur Tabi <timur@freescale.com>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without
++ * any warranty of any kind, whether express or implied.
++ */
++
++#ifndef __MPC5121_PSC_INFO_H__
++#define __MPC5121_PSC_INFO_H__
++
++extern struct mpc52xx_psc *psc_reg_priv;
++
++struct mpc5121_psc_info {
++ unsigned int id;
++ void __iomem *psc;
++ dma_addr_t phys;
++ unsigned int irq;
++ struct device *dev;
++ int rx_dma_gran;
++ int tx_dma_gran;
++};
++
++/**
++ * mpc5121_psc_private: per-PSC private data
++ *
++ * @name: short name for this device ("PSC0", "PSC1", etc)
++ * @psc: pointer to the PSC's registers
++ * @phys: physical address of the PSC registers
++ * @irq: IRQ of this PSC
++ * @dev: struct device pointer
++ * @playback: the number of playback streams opened
++ * @capture: the number of capture streams opened
++ * @cpu_dai: the CPU DAI for this device
++ * @format: the format of link
++ * @clk_dir: clock direction
++ */
++struct mpc5121_psc_private {
++ char name[8];
++ void __iomem *psc;
++ dma_addr_t phys;
++ unsigned int irq;
++ struct device *dev;
++ unsigned int playback;
++ unsigned int capture;
++ struct snd_soc_dai cpu_dai;
++ struct device_attribute dev_attr;
++ struct clk *clk;
++ int rx_dma_gran;
++ int tx_dma_gran;
++ int format;
++ int clk_dir;
++ int clk_rate;
++};
++
++/**
++ * mpc5121_ads_data: fabric-specific ASoC device data
++ *
++ * This structure contains data for a single sound platform device on an
++ * MPC5121e ADS. Some of the data is taken from the device tree.
++ */
++struct mpc5121_ads_data {
++ struct snd_soc_device sound_devdata;
++ struct snd_soc_dai_link dai;
++ struct snd_soc_card machine;
++ unsigned int dai_format;
++ unsigned int codec_clk_direction;
++ unsigned int cpu_clk_direction;
++ unsigned int clk_frequency;
++ struct mpc5121_psc_info psc_info;
++};
++
++struct snd_soc_dai *mpc5121_psc_create_dai(struct mpc5121_psc_info *);
++void mpc5121_psc_destroy_dai(struct snd_soc_dai *);
++int mpc5121_psc_init(struct device *dev, struct snd_soc_dai *cpu_dai);
++int mpc5121_psc_clkinit(struct mpc5121_psc_private *psc_private, int on);
++void mpc5121_psc_fifo_init(struct mpc5121_psc_private *psc_private);
++
++void mpc5121_ac97_reset(struct snd_ac97 *ac97);
++void mpc5121_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
++ unsigned short val);
++unsigned short mpc5121_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
++#endif /* __MPC5121_PSC_INFO_H__ */
--
1.7.3.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT
2011-04-08 19:33 [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT Jan Kobler
2011-04-08 19:33 ` [mpc5125-twr 2/2] Linux kernel for mpc5125-twr Jan Kobler
@ 2011-04-08 19:43 ` Tom Rini
2011-04-08 20:02 ` Jan Kobler
2011-04-08 20:15 ` mpc5125-twr: Tutorial Jan Kobler
2 siblings, 1 reply; 8+ messages in thread
From: Tom Rini @ 2011-04-08 19:43 UTC (permalink / raw)
To: openembedded-devel
On 04/08/2011 12:33 PM, Jan Kobler wrote:
> Freescale Development Kit TWR-MPC5125-KIT
>
> Vendor page: http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=TWR-MPC5125-KIT
>
> The name mpc5125-twr is used by Freescale in the Linux kernel for this board.
>
> Signed-off-by: Jan Kobler <eng1@koblersystems.de>
First, the linux_VER.bb change should be part of the patch that bring in
the patches for the board. Second, I see upstream there's a
mpc512x_defconfig. How much of this platform works upstream with a more
recent kernel? Thanks!
--
Tom Rini
Mentor Graphics Corporation
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT
2011-04-08 19:43 ` [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT Tom Rini
@ 2011-04-08 20:02 ` Jan Kobler
2011-04-08 21:37 ` Tom Rini
0 siblings, 1 reply; 8+ messages in thread
From: Jan Kobler @ 2011-04-08 20:02 UTC (permalink / raw)
To: openembedded-devel
Hi,
1. I wanted to make a clear distinction between what I have written and
what I have taken from
http://www.freescale.com/files/soft_dev_tools/software/board_support_packages/TWRMPC5125LinuxBSP.rar
which contains the Linux kernel 2.6.29-v2010041601 for the TWR-MPC5125-KIT.
Therefore linux_VER.bb is in [mpc5125-twr 1/2], because I have changed
it. Otherwise I would put it together in one patch.
2. I have tried to provide the same for Openembedded as Freescale is
currently shipping on their web page
http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=TWR-MPC5125-KIT&fpsp=1&tab=Design_Tools_Tab.
I have not tried to port it to a more recent kernel.
Is there already a more recent kernel, which contains mpc5125-twr support?
Best regards
Jan
^ permalink raw reply [flat|nested] 8+ messages in thread
* mpc5125-twr: Tutorial
2011-04-08 19:33 [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT Jan Kobler
2011-04-08 19:33 ` [mpc5125-twr 2/2] Linux kernel for mpc5125-twr Jan Kobler
2011-04-08 19:43 ` [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT Tom Rini
@ 2011-04-08 20:15 ` Jan Kobler
2011-04-08 23:56 ` Jan Kobler
2 siblings, 1 reply; 8+ messages in thread
From: Jan Kobler @ 2011-04-08 20:15 UTC (permalink / raw)
To: openembedded-devel
Hi,
1. I have described the usage and the current state of the BSP of the
new machine mpc5125-twr in a tutorial and wanted to publish it on
gentoo-wiki.com. Unfortunately gentoo-wiki.com is currently not accessible.
Here is the tutorial in text form.
2. I can provide it also as html file, if someone wants it.
3. I would like to publish this tutorial under
http://www.openembedded.org/index.php/Category:Machine
because I think this would be the right place for it.
How can I get write access to the openembedded-wiki?
Best regards
Jan
_________________________________________________________________
Openembedded for Freescale TWR-MPC5125
----------------------------------------------------------------------
Table of Contents
About this tutorial
Freescale TWR-MPC5125
Openembedded
Git Paths
Folder Names
Install Software for Openembedded
Install Bitbake
Install Openembedded
Update
Install the Patch for the Board Freescale TWR-MPC5125
Create the configuration file
Environment setup
Image minimal-image
Build Image
Linux Kernel
Create the Root File System
nfs server
Prepare the Board
Serial Port
U-boot
Target Log
Status
Image opie-image
Build Image opie-image
Create the Root File System
NFS Server
U-boot
Target Log
Status
Screenshots
Image x11-gpe-image
Build Image x11-gpe-image
Create the Root File System
NFS Server
U-boot
Target Log
Status
Screenshots
Image xfce46-image
Build Image xfce46-image
Create the Root File System
NFS Server
U-boot
Start Xfce
Target Log
Status
Troubleshooting
Workaround when fetch fails
Workaround for cannot stat error
Bitbake Reports an Error
About this tutorial
This tutorial describes all the steps which are needed to create the
linux
kernel and different root file systems on a Gentoo Linux host for the
board Freescale TWR-MPC5125 with Openembedded, a build framework for
embedded Linux. The Linux Distribution Angstrom, which is part of
Openembedded, is used here to create the linux kernel and to create
several root file systems:
o a minimal-image for testing purposes,
o OPIE (Open Palmtop Integrated Environment), a graphical user
interface
for PDAs,
o GPE (GPE Palmtop Environment), a graphical user interface for
PDAs and
o Xfce, a lightweight desktop environment.
The minimal-image uses about 35MB RAM at runtime on the Freescale
TWR-MPC5125. OPIE uses about 51MB RAM at runtime. GPE uses about 61MB RAM
at runtime. Xfce uses about 95MB RAM at runtime.
Note: This is the first release of a BSP for the board Freescale
TWR-MPC5125 in Openembedded. It seems to work, but only few tests have
been made so far.
Freescale TWR-MPC5125
The Freescale TWR-MPC5125-KIT consists of one MPU module and a peripheral
module which can be plugged between two backplane boards. On the MPU
module is the Freescale MPC5125 with a Power Architecture e300c4 core.
Freescale provides a Linux demo and the source code for the Linux kernel
and for U-boot.
Freescale TWR-MPC5125:
http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=TWR-MPC5125-KIT
Freescale MPC5125:
http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MPC5125
TowerGeeks Group for TWR-MPC5125:
http://www.towergeeks.org/group/twrmpc5125
Openembedded
You can find further explanations for the following steps in the
Openembedded wiki: http://wiki.openembedded.org/index.php/Main_Page.
How to install Openembedded on Gentoo Linux:
http://www.openembedded.org/index.php/OEandYourDistro#Gentoo_instructions
How to get started: http://www.openembedded.org/index.php/Getting_started
Advanced configuration settings:
http://www.openembedded.org/index.php/Advanced_configuration
User manual: http://docs.openembedded.org/usermanual/usermanual.html
Git Paths
The source code of the Openembedded project is saved in git-repositories:
http://cgit.openembedded.org/cgit.cgi
The source code of the bitbake application:
http://cgit.openembedded.org/cgit.cgi/bitbake/
You can look at each source file:
http://cgit.openembedded.org/cgit.cgi/bitbake/tree/
The configuration files and the defintions of the software packages:
http://cgit.openembedded.org/cgit.cgi/openembedded/
You can look at each file:
http://cgit.openembedded.org/cgit.cgi/openembedded/tree
Config files for the supported hardware:
http://cgit.openembedded.org/cgit.cgi/openembedded/tree/conf/machine
Patches for openembedded:
http://patches.openembedded.org/project/oe/list/
Apply patches: http://wiki.openembedded.net/index.php/Patchwork
Folder Names
These folders are used for
Bitbake: $MY_BITBAKE
Openembedded: $MY_OPENEMBEDDED
Project configuration: $MY_PROJECT
Build: $MY_TMP
NFSRoot: $MY_NFSROOT
Source: $MY_SRC
The application bitbake is installed into the folder $MY_BITBAKE.
The project definitions of openembedded are installed into the folder
$MY_OPENEMBEDDED.
Source files are downloaded by bitbake into the folder $MY_SRC.
The configuration files for the current project are created in the folder
$MY_PROJECT.
bitbake creates all files in the folder $MY_TMP.
The created root file systems are extracted in the folder $MY_NFSROOT and
can be mounted by the target via NFS.
The current project is just called test01.
Define environment variables:
export MY_BITBAKE=/MyOE/bitbake-1.12;
export MY_OPENEMBEDDED=/MyOE/openembedded;
export MY_PROJECT=/MyOE/project/test01;
export MY_TMP=/MyOE/tmp/test01;
export MY_NFSROOT=/MyOE/nfsroot/test01;
export MY_SRC=/usr/portage/distfiles;
Install Software for Openembedded
Before you can install and use openembedded, you need to install some
software. At first set the use flags.
nano /etc/portage/package.use/openembedded-use
New or changed content of file openembedded-use:
# use flags for openembedded
dev-util/quilt graphviz
Emerge the software, which is missing.
emerge --update --ask -v psyco patch make sed dev-lang/python m4 bison
cvs openjade \
quilt sgmltools-lite docbook-xml-dtd docbook-dsssl-stylesheets xmlto
docbook-sgml-utils \
libpcre boost subversion texi2html pysqlite chrpath diffstat
It is possible that portage requests that some other use flags are set
too. psyco is not available for gentoo amd64 i.e. x86_64.
Now you can check, if all needed applications exist
which libtool python2.6 git svn cvs make gcc g++ patch help2man
diffstat texi2html \
bzip2 gawk tar md5sum texi2pdf chrpath
texi2pdf is part of the package texinfo.
Install Bitbake
Create folders and download the branch 1.12 of bitbake:
mkdir -p $MY_BITBAKE;
git clone -b 1.12 git://git.openembedded.net/bitbake $MY_BITBAKE
The size of this folder is about 3MB.
Install Openembedded
Create folders and download the branch master of openembedded:
git clone git://git.openembedded.net/openembedded $MY_OPENEMBEDDED
The size of this folder is about 150MB.
Update
From time to time you need to update your local versions of openembedded
and bitbake.
Update Openembedded
cd $MY_OPENEMBEDDED;
git pull --rebase
Update Bitbake
cd $MY_BITBAKE;
git pull --rebase
Install the Patch for the Board Freescale TWR-MPC5125
Because Openembedded has so far no configuration files for the board
Freescale TWR-MPC5125, some patches need to be applied.
Note: The patches will be soon released and the URL announced.
When the patches are published on the Openembedded patch list
http://patches.openembedded.org/project/oe/list they can be easily
applied:
more $MY_OPENEMBEDDED/contrib/patchwork/pw-am.sh
cd $MY_OPENEMBEDDED;
$MY_OPENEMBEDDED/contrib/patchwork/pw-am.sh xxx yyy
Create the configuration file
For each project you should create a project folder with a configuration
file. Here it is $MY_PROJECT. Almost all settings for your project are
defined in the local.conf file. At first use the file
local.conf.sample as
template for the local.conf file.
mkdir -p $MY_PROJECT/conf;
cp $MY_OPENEMBEDDED/conf/local.conf.sample $MY_PROJECT/conf/local.conf
Then adjust the configuration file
nano $MY_PROJECT/conf/local.conf
New or changed content of file local.conf:
# DL_DIR = "${HOME}/sources"
# use the distfiles of gentoo
DL_DIR = "/usr/portage/distfiles"
Bitbake downloads source files into and creates md5 files in the folder
which is specified by the environment variable DL_DIR. Portage and
bitbake
download the same source files. You can define DL_DIR to point to the
source file repository of portage which is by default
/usr/portage/distfiles. This avoids downloading a file two times by
portage and bitbake. Make sure that you have access permissions to this
folder. If you don't want to use the same download folder, then choose
some other folder name for DL_DIR.
Note: I don't know if sharing the download folder is a real feature of
portage and openembedded, but it works for me. Sometimes when a fetch
fails, I use Workaround_when_fetch_fails
Continue adjusting the local.conf file. New or changed content of file
local.conf:
# BBFILES := "${@bb.fatal('Edit your conf/local.conf: BBFILES')}"
BBFILES = "/MyOE/openembedded/recipes/*/*.bb"
# on gentoo help2man unknown arg --no-discard-stderr
# ASSUME_PROVIDED += "help2man-native"
# TMPDIR = /usr/local/projects/oetmp
TMPDIR = /MyOE/tmp/test01
# TMPDIR is created by bitbake
# GLIBC_GENERATE_LOCALES = "en_US.UTF-8 en_GB.UTF-8 de_DE.UTF-8"
GLIBC_GENERATE_LOCALES = "en_US.UTF-8"
#IMAGE_FSTYPES = "jffs2 tar"
IMAGE_FSTYPES = "jffs2 tar"
# PARALLEL_MAKE = "-j 4"
PARALLEL_MAKE = "-j 4"
# BB_NUMBER_THREADS = "2"
BB_NUMBER_THREADS = "2"
Delete the last line of the file, otherwise you will get an error
message.
The value of the variable DISTRO is the name of a distribution. The
allowed values are the file names without suffix in the folder
$MY_OPENEMBEDDED/conf/distro.
ls $MY_OPENEMBEDDED/conf/distro
The value of the variable MACHINE is the name of a target board or target
system. The allowed values are the file names without suffix in the
folder
$MY_OPENEMBEDDED/conf/machine.
ls $MY_OPENEMBEDDED/conf/machine
Define distribution and machine. Here mpc5125-twr.conf fits best to
Freescale TWR-MPC5125.New or changed content of file local.conf:
DISTRO="angstrom"
MACHINE="mpc5125-twr"
Clean work folder after succesfully building.New or changed content of
file local.conf:
INHERIT += "rm_work"
Environment setup
Before you can call bitbake, you need to setup the environment. Because
each project can have its own environment, you should create a script in
the project folder.
nano $MY_PROJECT/setup-env
New or changed content of file setup-env:
export PATH="/MyOE/bitbake-1.12/bin:${PATH}"
export BBPATH="/MyOE/project/test01:/MyOE/openembedded/"
# you can set also here: BB_ENV_EXTRAWHITE
# set a new prompt
export PS1="test01 $PS1"
echo "Configure Openembedded for test01 "
Call the script file setup-env only once, before you start using bitbake.
The prompt will indicate, if you have called it or not.
All the settings in setup-env and local.conf are independent of the
environment variables MY_OPENEMBEDDED, MY_BITBAKE, MY_SRC, MY_NFSROOT,
MY_PROJECT. You don't need them to run bitbake.
Image minimal-image
Build Image
You can be in any folder you like. You should be logged in as a common
user. You don't need root privileges most of the time. Start building an
image
source $MY_PROJECT/setup-env;
bitbake minimal-image
Output:
Build Configuration:
BB_VERSION = "1.12.0"
METADATA_BRANCH = "master"
METADATA_REVISION = "6b9a381"
TARGET_ARCH = "ppc"
TARGET_OS = "linux"
MACHINE = "mpc5125-twr"
DISTRO = "angstrom"
DISTRO_VERSION = "v20110406"
At first all cross-tools (called native in openembedded), e.g. the
cross-compiler are build and installed in the folder $MY_TMP. Then the
cross-tools are used to build all needed software packages. Root file
images and the kernel images can be found in the folder
$MY_TMP/deploy/eglibc/images/mpc5125-twr/
ls -1s $MY_TMP/deploy/eglibc/images/mpc5125-twr/
These are the files which are created: Output:
7152
Angstrom-minimalist-image-eglibc-ipk-v20110406-mpc5125-twr.rootfs.jffs2
10668 Angstrom-minimalist-image-eglibc-ipk-v20110406-mpc5125-twr.rootfs.tar
6256
Angstrom-minimalist-image-eglibc-ipk-v20110406-mpc5125-twr.rootfs.tar.gz
6204 modules-2.6.29-r11-mpc5125-twr.tgz
2448 uImage-2.6.29-r11-mpc5125-twr.bin
12 uImage-2.6.29-r11-mpc5125-twr.dtb
These are the links which are created: Output:
minimalist-image-mpc5125-twr.jffs2 ->
Angstrom-minimalist-image-eglibc-ipk-v20110406-mpc5125-twr.rootfs.jffs2
minimalist-image-mpc5125-twr.tar ->
Angstrom-minimalist-image-eglibc-ipk-v20110406-mpc5125-twr.rootfs.tar
minimalist-image-mpc5125-twr.tar.gz ->
Angstrom-minimalist-image-eglibc-ipk-v20110406-mpc5125-twr.tar.gz
uImage-mpc5125-twr.bin -> uImage-2.6.29-r11-mpc5125-twr.bin
uImage-mpc5125-twr.dtb -> uImage-2.6.29-r11-mpc5125-twr.dtb
Linux Kernel
The board is already shipped with a Linux kernel in flash. U-boot can
load
the kernel from a TFTP server or from flash. Here we load the kernel from
a TFTP server.
cp
$MY_TMP/deploy/eglibc/images/mpc5125-twr/uImage-2.6.29-r11-mpc5125-twr.bin
/tftpboot/uImage-mpc5125-twr;
cp
$MY_TMP/deploy/eglibc/images/mpc5125-twr/uImage-2.6.29-r11-mpc5125-twr.dtb
/tftpboot/uImage-mpc5125-twr-dtb;
Create the Root File System
Take the rootfs image and extract it into another folder. The extraction
needs to be done with root privileges.
mkdir -p $MY_NFSROOT/mpc5125-twr-minimal-image;
cd $MY_NFSROOT/mpc5125-twr-minimal-image;
sudo tar xzf
$MY_TMP/deploy/eglibc/images/mpc5125-twr/minimalist-image-mpc5125-twr.tar.gz
Extract the kernel modules into the root file system.
cd $MY_NFSROOT/mpc5125-twr-minimal-image;
tar tzf
$MY_TMP/deploy/eglibc/images/mpc5125-twr/modules-2.6.29-r11-mpc5125-twr.tgz;
sudo rm -rf lib/modules/2.6.29.1;
sudo tar xzf
$MY_TMP/deploy/eglibc/images/mpc5125-twr/modules-2.6.29-r11-mpc5125-twr.tgz;
The rootfs can be now mounted via NFS.
nfs server
Configure the nfs server to export the rootfs
nano /etc/exports
New or changed content of file /etc/exports:
/MyOE/nfsroot/test01/mpc5125-twr-minimal-image
192.168.1.255/24(rw,no_root_squash,async,subtree_check)
exportfs -r
Prepare the Board
You need a monitor, a USB mouse, a USB keyboard and a USB Hub. Only the
TWR-MPC5125 MPU module is used.
o Connect the monitor to the HDMI port of the TWR-MPC5125 MPU module.
E.g. you can use a HDMI to DVI-D cable. The resolution has been
640x480 60Hz during the tests.
o Connect the mouse and the keyboard to a USB hub. Connect the USB hub
to the Mini-AB connector on the board which is next to the HDMI
connector. Use the Mini-B to receptable A cable.
o Connect a USB cable to your host computer and to the Mini-B connector
next to the SDHC card slot. This is the Serial-to-USB bridge.
o Connect an Ethernet cable to the board.
o Connect a 5V power supply to the board, if it is not already provided
by the USB cable to your host computer.
Serial Port
There is a Serial-to-USB bridge on the board, which connects the serial
port PSC0 to a USB port. When the Mini-B connector next to the SDHC card
slot on the board is connected to a USB port of the host, then this
message appears in /var/log/messages:Output:
usb 1-1.2: new full speed USB device using ehci_hcd and address 5
cdc_acm 1-1.2:1.0: This device cannot do calls on its own. It is not a
modem.
cdc_acm 1-1.2:1.0: ttyACM0: USB ACM device
usbcore: registered new interface driver cdc_acm
cdc_acm: v0.26:USB Abstract Control Model driver for USB modems and
ISDN adapters
Install the terminal application cu on your host system.
emerge -av taylor-uucp
Now open a terminal to the board
cu -l /dev/ttyACM0
U-boot
Use the Serial-to-USB bridge to connect to the serial port PSC0 of the
CPU. Boot the board and enter the command line of u-boot. Define the IP
address of the board, the IP address of the server and the path for
nfsroot. Check the current settings of the variables which are used to
boot the board.
echo ipaddr=$ipaddr;
echo gatewayip=$gatewayip;
echo netmask=$netmask;
echo serverip=$serverip;
echo kernel_loader=$kernel_loader_addr;
echo fdt_loader_addr=$fdt_loader_addr;
echo rootpath=$rootpath;
echo consoledev=$consoledev;
echo baudrate=$baudrate;
echo hostname=$hostname;
echo netdev=$netdev;
echo bootargs=$bootargs;
echo bootcmd=$bootcmd;
echo tftpboot=$tftpboot;
Change the variables which are used to boot the board.
setenv ipaddr 192.168.1.8;
setenv gatewayip 192.168.1.1;
setenv netmask 255.255.255.0;
setenv serverip 192.168.1.33;
setenv consoledev ttyPSC0;
setenv netdev eth0;
Define the command to load the kernel from a TFTP server.
set tftpboot 'tftp $kernel_loader_addr uImage-mpc5125-twr; tftp
$fdt_loader_addr uImage-mpc5125-twr-dtb; bootm $kernel_loader_addr -
$fdt_loader_addr '
Define the nfsroot path and the bootcmd argument. When you want to use a
different nfsroot, you need to change only rootpath and bootargs.
setenv rootpath /MyOE/nfsroot/test01/mpc5125-twr-minimal-image;
setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath}
console=${consoledev},${baudrate}
ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off
panic=1;
Save the new environment and boot again.
saveenv
run tftpboot
Target Log
The linux kernel specific part:
Output:
U-Boot 2009.03-00004-gd37ab38 (Apr 14 2010 - 10:48:22) MPC512X
CPU: MPC5125 rev. 1.0, Core e300c4 at 393.216 MHz, CSB at 196.608 MHz
board: mpc5125_mpu
I2C: ready
DRAM: 256 MB
NAND: 4096 MiB
In: serial
Out: serial
Err: serial
Net: FEC ETHERNET
Type "run flash_nfs" to mount root filesystem over NFS
Hit any key to stop autoboot: 0
=>
=> setenv ipaddr 192.168.1.8;
=> setenv gatewayip 192.168.1.1;
=> setenv netmask 255.255.255.0;
=> setenv serverip 192.168.1.33;
=> setenv consoledev ttyPSC0;
=> setenv netdev eth0;
=> set tftpboot 'tftp $kernel_loader_addr uImage-mpc5125-twr; tftp
$fdt_loader_addr uImage-mpc5125-twr-dtb; bootm $kernel_loader_addr -
$fdt_loader_addr '
=> setenv rootpath /MyOE/nfsroot/test01/mpc5125-twr-minimal-image;
=> setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath}
console=${consoledev},${baudrate}
ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off
panic=1;
=> echo $tftpboot
tftp $kernel_loader_addr uImage-mpc5125-twr; tftp $fdt_loader_addr
uImage-mpc5125-twr-dtb; bootm $kernel_loader_addr - $fdt_loader_addr
=> echo $rootpath
/MyOE/nfsroot/test01/mpc5125-twr-minimal-image
=> echo $bootargs
root=/dev/nfs rw
nfsroot=192.168.1.33:/MyOE/nfsroot/test01/mpc5125-twr-minimal-image
console=ttyPSC0,115200
ip=192.168.1.8:192.168.1.33:192.168.1.1:255.255.255.0:ads5125:eth0:off
panic=1
=> saveenv
Saving Environment to NAND...
Erasing Nand...
Writing to Nand... done
=> run tftpboot
Using FEC ETHERNET device
TFTP from server 192.168.1.33; our IP address is 192.168.1.8
Filename 'uImage-mpc5125-twr'.
Load address: 0x2000000
Loading: #################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#################################################################
##################################
done
Bytes transferred = 2499150 (26224e hex)
Using FEC ETHERNET device
TFTP from server 192.168.1.33; our IP address is 192.168.1.8
Filename 'uImage-mpc5125-twr-dtb'.
Load address: 0x2800000
Loading: ###
done
Bytes transferred = 12288 (3000 hex)
## Booting kernel from Legacy Image at 02000000 ...
Image Name: Angstrom/2.6.29/mpc5125-twr
Created: 2011-04-06 8:58:20 UTC
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 2499086 Bytes = 2.4 MB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
## Flattened Device Tree blob at 02800000
Booting using the fdt blob at 0x2800000
Uncompressing Kernel Image ... OK
Loading Device Tree to 007fa000, end 007fffff ... OK
boot_jump_linux line:101 60000000 60000000 60000000 2c050000
Using MPC5125 ADS machine description
Initializing cgroup subsys cpu
Linux version 2.6.29.1 (userA@hostX) (gcc version 4.5.3 20110311
(prerelease) (GCC) ) #1 PREEMPT Wed Apr 6 10:58:12 CEST 2011
MPC5125 ADS board from Freescale Semiconductor
preallocate_diu_videomemory: diu_size=5242880
preallocate_diu_videomemory: diu_mem=c07fc000
PSC0 psc_fifo_base:0 tx_fifo_size:00000060 rx_fifo_size:00000060
PSC1 psc_fifo_base:192 tx_fifo_size:00000004 rx_fifo_size:00000004
PSC9 psc_fifo_base:200 tx_fifo_size:00000004 rx_fifo_size:00000004
Zone PFN ranges:
DMA 0x00000000 -> 0x00010000
Normal 0x00010000 -> 0x00010000
Movable zone start PFN for each node
early_node_map[1] active PFN ranges
0: 0x00000000 -> 0x00010000
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 65024
Kernel command line: root=/dev/nfs rw
nfsroot=192.168.1.33:/MyOE/nfsroot/test01/mpc5125-twr-minimal-image
console=ttyPSC0,115200
ip=192.168.1.8:192.168.1.33:192.168.1.1:255.255.255.0:ads5125:eth0:off
panic=1
IPIC (128 IRQ sources) at fdffbc00
PID hash table entries: 1024 (order: 10, 4096 bytes)
clocksource: timebase mult[5161555] shift[22] registered
Console: colour dummy device 80x25
console [ttyPSC0] enabled
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
Memory: 248892k/262144k available (4912k kernel code, 12928k reserved,
192k data, 396k bss, 192k init)
Calibrating delay loop... 98.04 BogoMIPS (lpj=196096)
Mount-cache hash table entries: 512
Initializing cgroup subsys ns
Initializing cgroup subsys cpuacct
Initializing cgroup subsys devices
Initializing cgroup subsys freezer
Initializing cgroup subsys net_cls
net_namespace: 992 bytes
NET: Registered protocol family 16
Could not initialize clk spdif_txclk without a calc routine
Could not initialize clk spdif_rxclk without a calc routine
register :mscan0_clk
register :mscan1_clk
mapped ioctl to d1004000 and gpioctl to d1008100
PCI: Probing PCI hardware
bio: create slab <bio-0> at 0
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
Freescale Elo / Elo Plus DMA driver
Freescale(R) MPC5121 DMA Engine found, 64 channels
fsldma: Self-test copy successfully
NET: Registered protocol family 2
IP route cache hash table entries: 2048 (order: 1, 8192 bytes)
TCP established hash table entries: 8192 (order: 4, 65536 bytes)
TCP bind hash table entries: 8192 (order: 3, 32768 bytes)
TCP: Hash tables configured (established 8192 bind 8192)
TCP reno registered
NET: Registered protocol family 1
audit: initializing netlink socket (disabled)
type=2000 audit(0.329:1): initialized
NTFS driver 2.1.29 [Flags: R/W].
fuse init (API version 7.11)
yaffs Apr 6 2011 10:57:54 Installing.
msgmni has been set to 486
alg: No test for stdrng (krng)
Block layer SCSI generic (bsg) driver version 0.4 loaded (major 253)
io scheduler noop registered
io scheduler anticipatory registered (default)
io scheduler deadline registered
io scheduler cfq registered
fsl_diu_alloc: size=64
fsl_diu_alloc: size=1382400
Console: switching to colour frame buffer device 90x30
fb0: Panel0 fb device registered successfully.
fsl_diu_alloc: size=76800
fb1: Panel1 AOI0 fb device registered successfully.
fsl_diu_alloc: size=76800
fb2: Panel1 AOI1 fb device registered successfully.
fsl_diu_alloc: size=76800
fb3: Panel2 AOI0 fb device registered successfully.
fsl_diu_alloc: size=76800
fb4: Panel2 AOI1 fb device registered successfully.
fsl_diu_alloc: size=32768
FSL_DIU_FB: registed FB device driver!
Generic non-volatile memory driver v1.1
Serial: MPC52xx PSC UART driver
80011100.serial: ttyPSC0 at MMIO 0x80011100 (irq = 40) is a MPC52xx PSC
80011900.serial: ttyPSC1 at MMIO 0x80011900 (irq = 40) is a MPC52xx PSC
brd: module loaded
usbcore: registered new interface driver ub
vcan: Virtual CAN interface driver
fsl-mscan initializing
can0 (fsl-mscan): not using net_device_ops yet
fsl-mscan fsl-mscan.0: probe port 0xD102C300 done, clk rate:98500000
can1 (fsl-mscan): not using net_device_ops yet
fsl-mscan fsl-mscan.1: probe port 0xD1030380 done, clk rate:98500000
eth0 (fs_enet): not using net_device_ops yet
eth0: fs_enet: 00:11:22:33:44:55
FEC MII Bus: probed
Driver 'sd' needs updating - please use bus_type methods
Driver 'sr' needs updating - please use bus_type methods
SCSI Media Changer driver v0.25
Driver 'ch' needs updating - please use bus_type methods
MPC5125 MTD nand Driver 0.5
NAND device: Manufacturer ID: 0x2c, Chip ID: 0x68 (Micron NAND 4GiB
3,3V 8-bit)
mpc5125_nfc 40000000.nfc: Using OF partition info
Creating 9 MTD partitions on "MPC5125 NAND":
0x000000000000-0x000000100000 : "loader"
0x000000100000-0x000000200000 : "uboot"
0x000000200000-0x000000300000 : "envirment"
0x000000300000-0x000000b00000 : "kernel"
0x000000b00000-0x000000c00000 : "device-tree"
0x000000c00000-0x000001400000 : "rootfs"
0x000001400000-0x000080000000 : "filesystem"
0x000080000000-0x000086400000 : "mqx"
0x000086400000-0x000100000000 : "data"
ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
fsl-ehci fsl-ehci.0: Freescale On-Chip EHCI Host Controller
fsl-ehci fsl-ehci.0: new USB bus registered, assigned bus number 1
fsl-ehci fsl-ehci.0: irq 43, io mem 0x80003000
fsl-ehci fsl-ehci.0: USB 2.0 started, EHCI 1.00
usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
usb usb1: Product: Freescale On-Chip EHCI Host Controller
usb usb1: Manufacturer: Linux 2.6.29.1 ehci_hcd
usb usb1: SerialNumber: fsl-ehci.0
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
Initializing USB Mass Storage driver...
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
usbcore: registered new interface driver libusual
mice: PS/2 mouse device common for all mice
mpc5121-rtc 80000a00.rtc: rtc core: registered mpc5121-rtc as rtc0
sdhc: Freescale Enhanced Secure Digital Host Controller driver
mmc0: SDHC at 0x80001500 irq 23 PIO
usbcore: registered new interface driver hiddev
usbcore: registered new interface driver usbhid
usbhid: v2.6:USB HID core driver
Advanced Linux Sound Architecture Driver Version 1.0.18a.
Freescale MPC5121 ADS ALSA SoC fabric driver
No device for DAI AC97 HiFi
No device for DAI psc0
AC97 SoC Audio Codec 0.6
asoc: AC97 HiFi <-> psc0 mapping ok
ALSA device list:
#0: MPC5121 ADS (AC97)
TCP cubic registered
NET: Registered protocol family 17
can: controller area network core (rev 20090105 abi 8)
NET: Registered protocol family 29
can: raw protocol (rev 20090105)
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
registered taskstats version 1
mpc5121-rtc 80000a00.rtc: setting system clock to 2011-04-07 11:51:57
UTC (1302177117)
usb 1-1: new high speed USB device using fsl-ehci and address 2
usb 1-1: New USB device found, idVendor=05e3, idProduct=0608
usb 1-1: New USB device strings: Mfr=0, Product=1, SerialNumber=0
usb 1-1: Product: USB2.0 Hub
usb 1-1: configuration #1 chosen from 1 choice
hub 1-1:1.0: USB hub found
hub 1-1:1.0: 4 ports detected
usb 1-1.3: new low speed USB device using fsl-ehci and address 3
usb 1-1.3: New USB device found, idVendor=099a, idProduct=610c
usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-1.3: Product: USB Multimedia Keyboard
usb 1-1.3: Manufacturer:
usb 1-1.3: configuration #1 chosen from 1 choice
input: USB Multimedia Keyboard as
/devices/platform/fsl-ehci.0/usb1/1-1/1-1.3/1-1.3:1.0/input/input0
generic-usb 0003:099A:610C.0001: input,hidraw0: USB HID v1.00 Keyboard
[ USB Multimedia Keyboard ] on usb-fsl-ehci.0-1.3/input0
input: USB Multimedia Keyboard as
/devices/platform/fsl-ehci.0/usb1/1-1/1-1.3/1-1.3:1.1/input/input1
generic-usb 0003:099A:610C.0002: input,hidraw1: USB HID v1.00 Device [
USB Multimedia Keyboard ] on usb-fsl-ehci.0-1.3/input1
usb 1-1.4: new low speed USB device using fsl-ehci and address 4
usb 1-1.4: New USB device found, idVendor=15ca, idProduct=00c3
usb 1-1.4: New USB device strings: Mfr=0, Product=2, SerialNumber=0
usb 1-1.4: Product: USB Optical Mouse
usb 1-1.4: configuration #1 chosen from 1 choice
input: USB Optical Mouse as
/devices/platform/fsl-ehci.0/usb1/1-1/1-1.4/1-1.4:1.0/input/input2
generic-usb 0003:15CA:00C3.0003: input,hidraw2: USB HID v1.10 Mouse
[USB Optical Mouse] on usb-fsl-ehci.0-1.4/input0
IP-Config: Complete:
device=eth0, addr=192.168.1.8, mask=255.255.255.0, gw=192.168.1.1,
host=ads5125, domain=, nis-domain=(none),
bootserver=192.168.1.33, rootserver=192.168.1.33, rootpath=
Looking up port of RPC 100003/2 on 192.168.1.33
Looking up port of RPC 100005/1 on 192.168.1.33
VFS: Mounted root (nfs filesystem) on device 0:14.
Freeing unused kernel memory: 192k init
The minimal-image specific part:
Output:
INIT: version 2.86 booting
Please wait: booting...
Starting udev
WARNING: -e needs -E or -F
UnCorrectable RS-ECC Error
end_request: I/O error, dev mtdblock7, sector 248
Buffer I/O error on device mtdblock7, logical block 31
A lot of error messages: UnCorrectable RS-ECC ErrorOutput:
Remounting root file system...
Caching udev devnodes
Populating dev cache
NOT configuring network interfaces: / is an NFS mount
INIT: Entering runlevel: 5
Creating Dropbear SSH server RSA host key.
Will output 1024 bit rsa secret key to
'/etc/dropbear/dropbear_rsa_host_key'
Generating key, this may take a while...
Public key portion is:
ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAAAgwCjY0uE3muO0KOvrUe45Fsk+wY3ov4ZAdurgTqNbVzuIaKBAB3rqgHyas7VPTnjr79EmpokXtdQk6L5mBoouvVUIG1JocSiiEo+/w9bwcHXi82MFJlUUOG+z4ZXX5wVfnQ2+uIzzgZKo3FDs5B0GhSgKVY/oMcERVb4FEQ+xDJf7cfT
root@mpc5125-twr
Fingerprint: md5 20:6c:d5:6b:37:b6:28:be:f5:05:4d:2a:c2:ec:38:2f
Starting Dropbear SSH server: NET: Registered protocol family 10
lo: Disabled Privacy Extensions
dropbear.
Starting syslogd/klogd: done
.-------.
| | .-.
| | |-----.-----.-----.| | .----..-----.-----.
| | | __ | ---'| '--.| .-'| | |
| | | | | |--- || --'| | | ' | | | |
'---'---'--'--'--. |-----''----''--' '-----'-'-'-'
-' |
'---'
The Angstrom Distribution mpc5125-twr ttyPSC0
Angstromv20110406 mpc5125-twr ttyPSC0
INIT: Id "S" respawning too fast: disabled for 5 minutes
INIT: Id "1" respawning
INIT: no more processes
Login with ssh via Ethernet
uname -a
Output:
Linux mpc5125-twr 2.6.29.1 #1 PREEMPT Wed Apr 6 10:58:12 CEST 2011 ppc
GNU/Linux
cat /proc/cpuinfo
Output:
processor : 0
cpu : e300c4
clock : 393.216000MHz
revision : 1.0 (pvr 8086 2010)
bogomips : 98.04
timebase : 49152000
platform : MPC5125 ADS
model : mpc5125ads
Memory : 256 MB
top
Output:
Mem: 35776K used, 213632K free, 0K shrd, 0K buff, 24900K cached
Only the line with the memory usage. vmstat is not available.
cat /proc/meminfo
Output:
MemTotal: 249408 kB
MemFree: 213624 kB
Buffers: 0 kB
Cached: 24912 kB
SwapCached: 0 kB
Active: 4804 kB
Inactive: 21624 kB
Active(anon): 1804 kB
Inactive(anon): 0 kB
Active(file): 3000 kB
Inactive(file): 21624 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 1564 kB
Mapped: 1480 kB
Slab: 6020 kB
SReclaimable: 2792 kB
SUnreclaim: 3228 kB
PageTables: 216 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 124704 kB
Committed_AS: 4356 kB
VmallocTotal: 737256 kB
VmallocUsed: 1560 kB
VmallocChunk: 734460 kB
ps
Output:
PID USER VSZ STAT COMMAND
1 root 1864 S init [5]
2 root 0 SW< [kthreadd]
3 root 0 SW< [ksoftirqd/0]
4 root 0 SW< [events/0]
5 root 0 SW< [khelper]
6 root 0 SW< [netns]
7 root 0 SW< [kintegrityd/0]
8 root 0 SW< [kblockd/0]
9 root 0 SW< [ksuspend_usbd]
10 root 0 SW< [khubd]
11 root 0 SW< [kmmcd]
12 root 0 SW [pdflush]
13 root 0 SW [pdflush]
14 root 0 SW< [kswapd0]
15 root 0 SW< [aio/0]
16 root 0 SW< [nfsiod]
21 root 0 SW< [mtdblockd]
22 root 0 SW< [hid_compat]
27 root 0 SW< [rpciod/0]
50 root 2588 S < /sbin/udevd -d
131 root 2584 S < /sbin/udevd -d
132 root 2584 S < /sbin/udevd -d
342 root 2512 S /usr/sbin/dropbear -r
/etc/dropbear/dropbear_rsa_host_key -p 22
345 root 3420 S /sbin/syslogd -n -C64 -m 20
347 root 3356 S /sbin/klogd -n
390 root 2764 R /usr/sbin/dropbear -r
/etc/dropbear/dropbear_rsa_host_key -p 22
391 root 3612 S -sh
459 root 3612 R ps
Status
The image seems to work with one exception. Unfortunately getty reports a
Segmentation fault, when started. Therefore login via the devices
/dev/tty1 or /dev/ttyPSC0 is not possible. You can login to the board
only
with ssh via Ethernet.
ssh root@192.168.1.8
No password is needed.
Problem with getty
When getty is called in /etc/inittab, it is respawned. You can test it on
the command line:
getty 115200 /dev/tty1
Output:
Segmentation fault
Output on the display consoleOutput:
getty:ioctl() TIOCSPGRP call failed: Inappropriate ioctl for device
For the device /dev/ttyPSC0 a segmentation fault occurs too.
getty 115200 /dev/tty1
Output:
Segmentation fault
Image opie-image
Only the differences to Image_minimal-image are described.
Build Image opie-image
You can be in any folder you like. You should be logged in as a common
user.Call the script setup-env only once.
source $MY_PROJECT/setup-env
Start building the image.
bitbake opie-image
Root file images and the kernel images can be found in the folder
$MY_TMP/deploy/eglibc/images/mpc5125-twr/
ls -1s $MY_TMP/deploy/eglibc/images/mpc5125-twr/
Create the Root File System
Take the rootfs image and extract it into another folder. The extraction
needs to be done with root privileges.
mkdir -p $MY_NFSROOT/mpc5125-twr-opie-image;
cd $MY_NFSROOT/mpc5125-twr-opie-image;
sudo tar xzf
$MY_TMP/deploy/eglibc/images/mpc5125-twr/opie-image-mpc5125-twr.tar.gz
Extract the kernel modules into the root file system.
cd $MY_NFSROOT/mpc5125-twr-opie-image;
tar tzf
$MY_TMP/deploy/eglibc/images/mpc5125-twr/modules-2.6.29-r11-mpc5125-twr.tgz;
sudo rm -rf lib/modules/2.6.29.1;
sudo tar xzf
$MY_TMP/deploy/eglibc/images/mpc5125-twr/modules-2.6.29-r11-mpc5125-twr.tgz;
The rootfs can be now mounted via nfs.
NFS Server
Configure the NFS server to export the rootfs
nano /etc/exports
New or changed content of file /etc/exports:
/MyOE/nfsroot/test01/mpc5125-twr-opie-image
192.168.1.255/24(rw,no_root_squash,async,subtree_check)
exportfs -r
U-boot
Change the path of the root file system and the bootargs.
setenv rootpath /MyOE/nfsroot/test01/mpc5125-twr-opie-image;
setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath}
console=${consoledev},${baudrate}
ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off
panic=1
Save the new environment and boot the board again.
saveenv
run tftpboot
Target Log
The opie-image specific part:
Output:
Please wait: booting...
Starting udev
WARNING: -e needs -E or -F
Remounting root file system...
Caching udev devnodes
Populating dev cache
Configuring opie-pickboard.
Configuring opie-multikeyapplet.
Configuring opie-multikey.
Configuring update-modules.
Configuring opie-ttf-support.
Configuring ttf-dejavu-common.
Configuring ttf-dejavu-sans.
Configuring ttf-dejavu-sans-mono.
Configuring ppp.
Configuring ppp-dialin.
Segmentation fault
Configuring ntpdate.
adding crontab
Configuring e2fsprogs.
update-alternatives: Error: cannot register alternative chattr to
/usr/bin/chattr since it is already registered to /bin/chattr
update-alternatives: Linking //sbin/uuidd to uuidd.util-linux-ng
Configuring opie-screenshotapplet.
Configuring dbus.
Segmentation fault
chgrp: unknown group messagebus
adduser: group messagebus does not exist
chown: unknown user/group messagebus:messagebus
Segmentation fault
Adding system startup for /etc/init.d/dbus-1.
Configuring opie-brightnessapplet.
Configuring bluez4.
update-rc.d: /etc/init.d/bluetooth: file does not exist
Configuring opie-handwriting-classicset.
Configuring wpa-supplicant.
Configuring angstrom-libc-fixup-hack.
Configuring libnss-mdns.
Configuring avahi-daemon.
Segmentation fault
adduser: group avahi does not exist
Adding system startup for /etc/init.d/avahi-daemon.
Configuring avahi-autoipd.
Segmentation fault
adduser: group avahi-autoipd does not exist
Configuring opie-handwriting.
Configuring opie-volumeapplet.
Configuring opie-clockapplet.
Configuration for powerpc.generic not found, trying powerpc
NET: Registered protocol family 10
lo: Disabled Privacy Extensions
Collected errors:
* pkg_run_script: package "ppp-dialin" postinst script returned status
139.
* opkg_configure: ppp-dialin.postinst returned 139.
* pkg_run_script: package "avahi-autoipd" postinst script returned
status 1.
* opkg_configure: avahi-autoipd.postinst returned 1.
NOT configuring network interfaces: / is an NFS mount
Starting portmap daemon: portmap.
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
Checking for built-in Bluetooth: no
INIT: Entering runlevel: 5
chown: unknown user messagebus
Creating Dropbear SSH server RSA host key.
Will output 1024 bit rsa secret key to
'/etc/dropbear/dropbear_rsa_host_key'
Generating key, this may take a while...
Public key portion is:
ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAAAgnxdVwJ5zZuD3moquSOU0RfczAYZQo+vTkjomUmclxSW4Tn25yyyIAdwarZv5juPy1guXxbVppfYMoYvlcOOerCSL/+eXzJI48nhQ78MTHSZqx/8h05UF64i2GsKaV18IGhF3NuxkU01/Sz86nK+OpUCVmLmN2TU2Z8qvfxhcUqTHAU=
root@mpc5125-twr
Fingerprint: md5 db:e0:a9:6e:64:fa:e1:ef:85:8c:84:1c:40:ed:7e:d2
Starting Dropbear SSH server: dropbear.
Starting advanced power management daemon: No APM support in kernel
(failed.)
Starting syslogd/klogd: done
* Starting Avahi mDNS/DNS-SD Daemon: avahi-daemon
Timeout reached while wating for return value
Could not receive return value from daemon process.
...fail!
Copying default qpe.conf into /home/root/Settings/
Starting Opie....
OGlobal::creating global configuration instance.
OConfig::OConfig()
<unknown>: ODevice reports transformation to be 0
<unknown>: setting QWS_DISPLAY to 'Transformed:Rot0:0'
qt_init() - starting in daemon mode...
.-------.
| | .-.
| | |-----.-----.-----.| | .----..-----.-----.
| | | __ | ---'| '--.| .-'| | |
| | | | | |--- || --'| | | ' | | | |
'---'---'--'--'--. |-----''----''--' '-----'-'-'-'
-' |
'---'
The Angstrom Distribution mpc5125-twr ttyPSC0
Angstrom v20110406 mpc5125-twr ttyPSC0
INIT: Id "S" respawning
INIT: Id "1" respawning
INIT: no more processes
Login with ssh via Ethernet
uname -a
Output:
Linux mpc5125-twr 2.6.29.1 #1 PREEMPT Wed Apr 6 10:58:12 CEST 2011 ppc
GNU/Linux
vmstat
Output:
procs -----------memory---------- ---swap-- -----io---- -system--
----cpu----
r b swpd free buff cache si so bi bo in cs us sy
id wa
0 0 0 189988 0 39168 0 0 1 0 340 326 3 7
89 1
cat /proc/meminfo
Output:
MemTotal: 249408 kB
MemFree: 189988 kB
Buffers: 0 kB
Cached: 39168 kB
SwapCached: 0 kB
Active: 19668 kB
Inactive: 29464 kB
Active(anon): 10300 kB
Inactive(anon): 0 kB
Active(file): 9368 kB
Inactive(file): 29464 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 10012 kB
Mapped: 7620 kB
Slab: 6668 kB
SReclaimable: 3384 kB
SUnreclaim: 3284 kB
PageTables: 324 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 124704 kB
Committed_AS: 16032 kB
VmallocTotal: 737256 kB
VmallocUsed: 1560 kB
VmallocChunk: 734504 kB
ps aux
Output:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.2 0.2 1864 656 ? Ss 11:48 0:01 init [5]
root 2 0.0 0.0 0 0 ? S< 11:48 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S< 11:48 0:00
[ksoftirqd/0]
root 4 0.0 0.0 0 0 ? S< 11:48 0:00 [events/0]
root 5 0.0 0.0 0 0 ? S< 11:48 0:00 [khelper]
root 6 0.0 0.0 0 0 ? S< 11:48 0:00 [netns]
root 7 0.0 0.0 0 0 ? S< 11:48 0:00
[kintegrityd/0]
root 8 0.0 0.0 0 0 ? S< 11:48 0:00
[kblockd/0]
root 9 0.0 0.0 0 0 ? S< 11:48 0:00
[ksuspend_usbd]
root 10 0.0 0.0 0 0 ? S< 11:48 0:00 [khubd]
root 11 4.3 0.0 0 0 ? S< 11:48 0:19 [kmmcd]
root 12 0.0 0.0 0 0 ? S 11:48 0:00 [pdflush]
root 13 0.0 0.0 0 0 ? S 11:48 0:00 [pdflush]
root 14 0.0 0.0 0 0 ? S< 11:48 0:00 [kswapd0]
root 15 0.0 0.0 0 0 ? S< 11:48 0:00 [aio/0]
root 16 0.0 0.0 0 0 ? S< 11:48 0:00 [nfsiod]
root 21 0.0 0.0 0 0 ? S< 11:48 0:00
[mtdblockd]
root 22 0.0 0.0 0 0 ? S< 11:48 0:00
[hid_compat]
root 27 0.1 0.0 0 0 ? S< 11:48 0:00 [rpciod/0]
root 50 0.1 0.2 2588 712 ? S<s 11:48 0:00
/sbin/udevd -d
root 97 0.0 0.3 2584 768 ? S< 11:48 0:00
/sbin/udevd -d
root 114 0.0 0.3 2584 752 ? S< 11:48 0:00
/sbin/udevd -d
daemon 638 0.0 0.1 1852 412 ? Ss 11:48 0:00
/sbin/portmap
root 673 0.0 0.1 2512 496 ? Ss 11:48 0:00
/usr/sbin/dropbear -r /etc/dropbear/dropbear_rsa_host_key -p 22
root 678 0.0 0.3 3420 812 ? Ss 11:48 0:00
/sbin/syslogd -n -C64 -m 20
root 680 0.0 0.2 3356 740 ? Ss 11:48 0:00
/sbin/klogd -n
root 702 0.0 0.1 3360 316 ? S 11:48 0:00
/bin/sh /etc/rc5.d/S99opie start
root 758 3.3 5.3 24388 13296 ? S 11:54 0:02 qpe
root 760 0.1 1.2 9196 3152 ? S< 11:54 0:00 qss
root 761 0.1 2.0 12344 5132 ? SN 11:54 0:00
quicklauncher
root 762 1.1 0.3 2764 972 ? Ss 11:55 0:00
/usr/sbin/dropbear -r /etc/dropbear/dropbear_rsa_host_key -p 22
root 763 0.1 0.4 3612 1016 pts/0 Ss 11:55 0:00 -sh
root 768 0.0 0.4 2668 1000 pts/0 R+ 11:55 0:00 ps aux
In the GUI you can select Application -> Systeminfo -> Benchmark and run
some benchmarks. Here are the results:Output:
Integer Arithmetic 1161170 dhrys
Floating Point Unit 0.09 secs
Text Rendering 1285 chars/sec
Gfx Rendering 3324.75.00gops/sec
RAM Performance 62.00 MB/s; 44.64 MB/s
Status
The GUI of OPIE appears on the screen and can be controlled by the mouse
and the keyboard. A small black rectangle appears in the upper left
corner. Several errors like missing group names are reported, when
booting, but the GUI appears and can be used. This is just a starting
point for using OPIE. Unfortunately getty reports a Segmentation fault,
when started. Therefore login via the devices /dev/ttyPSC0 or
/dev/tty1 is
not possible.
Screenshots
A screenshot can be found at
http://en.wikipedia.org/wiki/OPIE_user_interface.
Image x11-gpe-image
Only the differences to Image_minimal-image are described.
Build Image x11-gpe-image
You can be in any folder you like. You should be logged in as a common
user.Call the script setup-env only once.
source $MY_PROJECT/setup-env
Start building the image.
bitbake x11-gpe-image
Root file images and the kernel images can be found in the folder
$MY_TMP/deploy/eglibc/images/mpc5125-twr/
ls -1s $MY_TMP/deploy/eglibc/images/mpc5125-twr/
Create the Root File System
Take the rootfs image and extract it into another folder. The extraction
needs to be done with root privileges.
mkdir -p $MY_NFSROOT/mpc5125-twr-x11-gpe-image;
cd $MY_NFSROOT/mpc5125-twr-x11-gpe-image;
sudo tar xzf
$MY_TMP/deploy/eglibc/images/mpc5125-twr/x11-gpe-image-mpc5125-twr.tar.gz
Extract the kernel modules into the root file system.
cd $MY_NFSROOT/mpc5125-twr-x11-gpe-image;
tar tzf
$MY_TMP/deploy/eglibc/images/mpc5125-twr/modules-2.6.29-r11-mpc5125-twr.tgz;
sudo rm -rf lib/modules/2.6.29.1;
sudo tar xzf
$MY_TMP/deploy/eglibc/images/mpc5125-twr/modules-2.6.29-r11-mpc5125-twr.tgz;
The rootfs can be now mounted via nfs.
NFS Server
Configure the NFS server to export the rootfs
nano /etc/exports
New or changed content of file /etc/exports:
/MyOE/nfsroot/test01/mpc5125-twr-x11-gpe-image
192.168.1.255/24(rw,no_root_squash,async,subtree_check)
exportfs -r
U-boot
Change the path of the root file system and the bootargs.
setenv rootpath /MyOE/nfsroot/test01/mpc5125-twr-x11-gpe-image;
setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath}
console=${consoledev},${baudrate}
ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off
panic=1
Save the new environment and boot the board again.
saveenv
run tftpboot
Target Log
The x11-gpe-image specific part:
Output:
INIT: version 2.86 booting
Please wait: booting...
Starting udev
WARNING: -e needs -E or -F
Remounting root file system...
Caching udev devnodes
Populating dev cache
Undefined users:
Skipping /etc/default/volatiles/99_hal
Configuring hicolor-icon-theme.
Configuring pango-module-basic-x.
Configuring pango-module-basic-fc.
Configuring ttf-dejavu-common.
Configuring ttf-dejavu-sans.
Configuring gdk-pixbuf-loader-png.
Configuring gdk-pixbuf-loader-jpeg.
Configuring gdk-pixbuf-loader-gif.
Configuring gdk-pixbuf-loader-xpm.
Configuring dbus.
Segmentation fault
chgrp: unknown group messagebus
adduser: group messagebus does not exist
chown: unknown user/group messagebus:messagebus
Segmentation fault
Adding system startup for /etc/init.d/dbus-1.
Configuring policykit.
Segmentation fault
adduser: group polkituser does not exist
Configuring ntpdate.
adding crontab
Configuring update-modules.
Configuring ppp.
Configuring ppp-dialin.
Segmentation fault
Configuring e2fsprogs.
update-alternatives: Error: cannot register alternative chattr to
/usr/bin/chattr since it is already registered to /bin/chattr
update-alternatives: Linking //sbin/uuidd to uuidd.util-linux-ng
Configuring ttf-dejavu-sans-mono.
Configuring bluez4.
update-rc.d: /etc/init.d/bluetooth: file does not exist
Configuring wpa-supplicant.
Configuring angstrom-libc-fixup-hack.
Configuring libnss-mdns.
Configuring avahi-daemon.
Segmentation fault
adduser: group avahi does not exist
Adding system startup for /etc/init.d/avahi-daemon.
Configuring avahi-autoipd.
Segmentation fault
adduser: group avahi-autoipd does not exist
Configuring hal.
Segmentation fault
adduser: group haldaemon does not exist
Undefined users:
Skipping /etc/default/volatiles/99_hal
Configuration for powerpc.generic not found, trying powerpc
NET: Registered protocol family 10
lo: Disabled Privacy Extensions
Collected errors:
* pkg_run_script: package "ppp-dialin" postinst script returned status
139.
* opkg_configure: ppp-dialin.postinst returned 139.
* pkg_run_script: package "avahi-autoipd" postinst script returned
status 1.
* opkg_configure: avahi-autoipd.postinst returned 1.
NOT configuring network interfaces: / is an NFS mount
Starting portmap daemon: portmap.
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
Checking for built-in Bluetooth: no
INIT: Entering runlevel: 5
Starting system message bus: start-stop-daemon: unknown user messagebus
Creating Dropbear SSH server RSA host key.
Will output 1024 bit rsa secret key to
'/etc/dropbear/dropbear_rsa_host_key'
Generating key, this may take a while...
Public key portion is:
ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAAAgwCNJll+8PxiR1VoBxKHxIdwPml8w7TV1CwrUAySlN4Rj5T732hWROJRjAzhVyBfcdE7Lqis2o7dw+UIQigw1+JwkayO1MWIezABLHbQr5k9mrnYPjGdLPmp/yauxul8pNYAS/7DhOvq3g7OcppYGFjU33QK80xIdZUA+VV8H/lsKjQF
root@mpc5125-twr
Fingerprint: md5 a3:41:e1:72:58:15:22:82:bc:73:43:4e:bc:94:86:1d
Starting Dropbear SSH server: dropbear.
Starting syslogd/klogd: done
* Starting Avahi mDNS/DNS-SD Daemon: avahi-daemon
Timeout reached while wating for return value
Could not receive return value from daemon process.
...fail!
Starting GPE display manager: gpe-dm
.-------.
| | .-.
| | |-----.-----.-----.| | .----..-----.-----.
| | | __ | ---'| '--.| .-'| | |
| | | | | |--- || --'| | | ' | | | |
'---'---'--'--'--. |-----''----''--' '-----'-'-'-'
-' |
'---'
The Angstrom Distribution mpc5125-twr ttyPSC0
Angstrom v20110406 mpc5125-twr ttyPSC0
mpc5125-twr login:
INIT: Id "S" respawning too fast: disabled for 5 minutes
INIT: Id "1" respawning
INIT: no more processes
Login with ssh via Ethernet
uname -a
Output:
Linux mpc5125-twr 2.6.29.1 #1 PREEMPT Wed Apr 6 10:58:12 CEST 2011 ppc
GNU/Linux
vmstat
Output:
procs -----------memory---------- ---swap-- -----io---- -system--
----cpu----
r b swpd free buff cache si so bi bo in cs us sy
id wa
2 0 0 169732 0 50604 0 0 2 0 817 771 13 16
69 3
cat /proc/meminfo
Output:
MemTotal: 249408 kB
MemFree: 169732 kB
Buffers: 0 kB
Cached: 50604 kB
SwapCached: 0 kB
Active: 31512 kB
Inactive: 36624 kB
Active(anon): 17936 kB
Inactive(anon): 0 kB
Active(file): 13576 kB
Inactive(file): 36624 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 17580 kB
Mapped: 12340 kB
Slab: 7520 kB
SReclaimable: 3972 kB
SUnreclaim: 3548 kB
PageTables: 644 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 124704 kB
Committed_AS: 33296 kB
VmallocTotal: 737256 kB
VmallocUsed: 1560 kB
VmallocChunk: 734648 kB
ps aux
Output:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.5 0.2 1864 656 ? Ss 12:28 0:00 init [5]
root 2 0.0 0.0 0 0 ? S< 12:28 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S< 12:28 0:00
[ksoftirqd/0]
root 4 0.0 0.0 0 0 ? S< 12:28 0:00 [events/0]
root 5 0.0 0.0 0 0 ? S< 12:28 0:00 [khelper]
root 6 0.0 0.0 0 0 ? S< 12:28 0:00 [netns]
root 7 0.0 0.0 0 0 ? S< 12:28 0:00
[kintegrityd/0]
root 8 0.0 0.0 0 0 ? S< 12:28 0:00
[kblockd/0]
root 9 0.0 0.0 0 0 ? S< 12:28 0:00
[ksuspend_usbd]
root 10 0.0 0.0 0 0 ? S< 12:28 0:00 [khubd]
root 11 4.4 0.0 0 0 ? D< 12:28 0:07 [kmmcd]
root 12 0.0 0.0 0 0 ? S 12:28 0:00 [pdflush]
root 13 0.0 0.0 0 0 ? S 12:28 0:00 [pdflush]
root 14 0.0 0.0 0 0 ? S< 12:28 0:00 [kswapd0]
root 15 0.0 0.0 0 0 ? S< 12:28 0:00 [aio/0]
root 16 0.1 0.0 0 0 ? S< 12:28 0:00 [nfsiod]
root 21 0.0 0.0 0 0 ? S< 12:28 0:00
[mtdblockd]
root 22 0.0 0.0 0 0 ? S< 12:28 0:00
[hid_compat]
root 27 0.4 0.0 0 0 ? S< 12:28 0:00 [rpciod/0]
root 50 0.3 0.2 2588 716 ? S<s 12:28 0:00
/sbin/udevd -d
root 112 0.0 0.3 2584 764 ? S< 12:28 0:00
/sbin/udevd -d
root 113 0.0 0.3 2584 764 ? S< 12:28 0:00
/sbin/udevd -d
daemon 866 0.0 0.1 1852 412 ? Ss 12:29 0:00
/sbin/portmap
root 901 0.0 0.1 2512 496 ? Ss 12:29 0:00
/usr/sbin/dropbear -r /etc/dropbear/dropbear_rsa_host_key -p 22
root 904 0.0 0.3 3420 812 ? Ss 12:29 0:00
/sbin/syslogd -n -C64 -m 20
root 906 0.0 0.2 3356 740 ? Ss 12:29 0:00
/sbin/klogd -n
root 917 0.0 0.1 3140 412 ? Ss 12:29 0:00 gpe-dm
root 919 4.9 3.9 24456 9860 tty2 Ss+ 12:29 0:06 Xorg
-br -pn -dpi 100 :0 -noreset
root 921 0.0 0.2 3356 676 ? S 12:29 0:00
run-parts /etc/X11/Xinit.d
userA 999 1.8 1.8 11400 4556 ? Ss 12:29 0:02
matchbox-window-manager -use_cursor yes
userA 1040 0.0 0.3 4444 752 ? S 12:30 0:00
/usr/bin/dbus-launch --auto-syntax --exit-with-session
userA 1041 0.0 0.3 2892 764 ? Ss 12:30 0:00
/usr/bin/dbus-daemon --fork --print-pid 5 --print-address 8 --session
userA 1045 0.5 3.0 20324 7724 ? S 12:30 0:00
gpe-login --autolock
userA 1052 0.1 0.7 5784 1908 ? S 12:30 0:00 gpe-confd
userA 1053 0.1 0.6 7024 1616 ? S 12:30 0:00
mb-applet-startup-monitor
userA 1054 0.0 0.3 3880 796 ? Ss 12:30 0:00
/usr/bin/ipaq-sleep
userA 1066 2.7 1.7 9756 4468 ? S 12:30 0:02
matchbox-desktop
userA 1067 0.6 1.1 7912 2976 ? S 12:30 0:00
matchbox-panel --no-flip --orientation south
userA 1071 0.1 1.0 5436 2556 ? S 12:30 0:00
/usr/libexec/gconfd-2
userA 1075 0.4 1.0 7888 2740 ? S 12:30 0:00
mb-applet-menu-launcher
userA 1077 0.2 1.0 7388 2496 ? S 12:30 0:00 mbinputmgr
userA 1079 0.1 0.6 7104 1624 ? S 12:30 0:00
mb-applet-battery
userA 1081 0.5 3.0 20676 7716 ? S 12:30 0:00 minilite
root 1084 1.3 0.3 2764 968 ? Ss 12:31 0:00
/usr/sbin/dropbear -r /etc/dropbear/dropbear_rsa_host_key -p 22
root 1085 0.2 0.4 3612 1036 pts/0 Ss 12:31 0:00 -sh
root 1090 0.0 0.4 2668 1000 pts/0 R+ 12:31 0:00 ps aux
Status
The GUI of GPE appears on the screen and can be controlled by the mouse
and keyboard. A small black rectangle appears in the upper left corner of
the display. Several errors like missing group names are reported, when
booting, but the GUI appears and can be used. This is just a starting
point for using GPE. Unfortunately getty reports a Segmentation fault,
when started. Therefore login via the devices /dev/ttyPSC0 or
/dev/tty1 is
not possible. You can login to the board with ssh via Ethernet.
Screenshots
Screenshots can be found here
http://gpe.linuxtogo.org/gallery/gallery/view_album.php?set_albumName=Applications.
Image xfce46-image
Only the differences to Image_minimal-image are described.
Build Image xfce46-image
You can be in any folder you like. You should be logged in as a common
user.Call the script setup-env only once.
source $MY_PROJECT/setup-env
Start building the image.
bitbake xfce46-image
Root file images and the kernel images can be found in the folder
$MY_TMP/deploy/eglibc/images/mpc5125-twr/
ls -1s $MY_TMP/deploy/eglibc/images/mpc5125-twr/
Create the Root File System
Take the rootfs image and extract it into another folder. The extraction
needs to be done with root privileges.
mkdir -p $MY_NFSROOT/mpc5125-twr-xfce46-image;
cd $MY_NFSROOT/mpc5125-twr-xfce46-image;
sudo tar xzf
$MY_TMP/deploy/eglibc/images/mpc5125-twr/xfce46-image-mpc5125-twr.tar.gz
Extract the kernel modules into the root file system.
cd $MY_NFSROOT/mpc5125-twr-xfce46-image;
tar tzf
$MY_TMP/deploy/eglibc/images/mpc5125-twr/modules-2.6.29-r11-mpc5125-twr.tgz;
sudo rm -rf lib/modules/2.6.29.1;
sudo tar xzf
$MY_TMP/deploy/eglibc/images/mpc5125-twr/modules-2.6.29-r11-mpc5125-twr.tgz;
The rootfs can be now mounted via nfs.
NFS Server
Configure the NFS server to export the rootfs
nano /etc/exports
New or changed content of file /etc/exports:
/MyOE/nfsroot/test01/mpc5125-twr-xfce46-image
192.168.1.255/24(rw,no_root_squash,async,subtree_check)
exportfs -r
U-boot
Change the path of the root file system and the bootargs.
setenv rootpath /MyOE/nfsroot/test01/mpc5125-twr-xfce46-image;
setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath}
console=${consoledev},${baudrate}
ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off
panic=1
Save the new environment and boot the board again.
saveenv
run tftpboot
Start Xfce
Login as root, check the current settings of the nameserver and adjust
them, if needed.
cat /etc/resolv.conf
echo "nameserver 192.168.1.1" >/etc/resolv.conf
Start the GUI.
startxfce4 &
Target Log
The xfce46-image specific part:
Output:
INIT: version 2.86 booting
Please wait: booting...
Starting udev
WARNING: -e needs -E or -F
Remounting root file system...
Caching udev devnodes
Populating dev cache
Undefined users:
Skipping /etc/default/volatiles/99_hal
Configuring hicolor-icon-theme.
Configuring dbus.
Segmentation fault
chgrp: unknown group messagebus
adduser: group messagebus does not exist
chown: unknown user/group messagebus:messagebus
Segmentation fault
Adding system startup for /etc/init.d/dbus-1.
Configuring pango-module-basic-x.
Configuring pango-module-basic-fc.
Configuring ttf-dejavu-common.
Configuring ttf-dejavu-sans.
Configuring gdk-pixbuf-loader-png.
Configuring gdk-pixbuf-loader-jpeg.
Configuring gdk-pixbuf-loader-gif.
Configuring gdk-pixbuf-loader-xpm.
Configuring libxfcegui4-4.
Configuring policykit.
Segmentation fault
adduser: group polkituser does not exist
Configuring gnome-keyring.
Configuring hal.
Segmentation fault
adduser: group haldaemon does not exist
Undefined users:
Skipping /etc/default/volatiles/99_hal
Configuring bluez4.
update-rc.d: /etc/init.d/bluetooth: file does not exist
Configuring xfwm4.
update-alternatives: Linking //usr/bin/x-window-manager to
/usr/bin/xfce4-session
Configuring update-modules.
Configuring xfce4-panel.
Configuring xfce4-panel-plugin-separator.
Configuring exo.
Configuring ppp.
Configuring ppp-dialin.
Segmentation fault
Configuring xfce-utils.
Configuring e2fsprogs.
update-alternatives: Error: cannot register alternative chattr to
/usr/bin/chattr since it is already registered to /bin/chattr
update-alternatives: Linking //sbin/uuidd to uuidd.util-linux-ng
Configuring xfprint.
Configuring thunar.
Configuring xfce4-appfinder.
Configuring xfce4-notifyd.
Configuring xfce4-session.
Configuring xfdesktop.
Configuring xfce4-panel-plugin-clock.
Configuring xfce4-panel-plugin-iconbox.
Configuring xfce4-panel-plugin-systray.
Configuring xfce-terminal.
Configuring midori.
Configuring orage.
Configuring squeeze.
Configuring ristretto.
Configuring angstrom-libc-fixup-hack.
Configuring libnss-mdns.
Configuring avahi-daemon.
Segmentation fault
adduser: group avahi does not exist
Adding system startup for /etc/init.d/avahi-daemon.
Configuring avahi-autoipd.
Segmentation fault
adduser: group avahi-autoipd does not exist
Configuration for powerpc.generic not found, trying powerpc
NET: Registered protocol family 10
lo: Disabled Privacy Extensions
Collected errors:
* pkg_run_script: package "ppp-dialin" postinst script returned status
139.
* opkg_configure: ppp-dialin.postinst returned 139.
* pkg_run_script: package "avahi-autoipd" postinst script returned
status 1.
* opkg_configure: avahi-autoipd.postinst returned 1.
NOT configuring network interfaces: / is an NFS mount
Starting portmap daemon: portmap.
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
INIT: Entering runlevel: 5
chown: unknown user messagebus
Creating Dropbear SSH server RSA host key.
Will output 1024 bit rsa secret key to
'/etc/dropbear/dropbear_rsa_host_key'
Generating key, this may take a while...
Public key portion is:
ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAAAgnNDJQjm83pY+GAUl01g+mL6ivTSDFW2IwkXdZgimbDnNSLrdiLTTxn7H1C35CEhP1tvRpQbW3LP6hDiNtlbjwH4qKWERBo2FSMVBb0pBJyMlaw0i/ZLawSHb6t+zMdoYiY6+5uhvkS4Zj6qYWwb9s1wYZVSKp/lUzQ+rpp0I8iT51c=
root@mpc5125-twr
Fingerprint: md5 39:dc:e2:4c:54:83:4a:b0:e6:2c:9f:4e:7d:14:8a:22
Starting Dropbear SSH server: dropbear.
Starting Samba: smbd nmbd.
Starting syslogd/klogd: done
* Starting Avahi mDNS/DNS-SD Daemon: avahi-daemon
Timeout reached while wating for return value
Could not receive return value from daemon process.
...fail!
.-------.
| | .-.
| | |-----.-----.-----.| | .----..-----.-----.
| | | __ | ---'| '--.| .-'| | |
| | | | | |--- || --'| | | ' | | | |
'---'---'--'--'--. |-----''----''--' '-----'-'-'-'
-' |
'---'
The Angstrom Distribution mpc5125-twr ttyPSC0
Angstrom v20110406 mpc5125-twr ttyPSC0
mpc5125-twr login:
INIT: Id "S" respawning too fast: disabled for 5 minutes
INIT: Id "1" respawning
INIT: no more processes
Login with ssh via Ethernet
uname -a
Output:
Linux mpc5125-twr 2.6.29.1 #1 PREEMPT Wed Apr 6 10:58:12 CEST 2011 ppc
GNU/Linux
cat /etc/resolv.conf
echo "nameserver 192.168.1.1" >/etc/resolv.conf
cat /etc/resolv.conf
Output:
nameserver 192.168.1.1
startxfce4 &
Output:
/usr/bin/startxfce4: Starting X server
X.Org X Server 1.9.4
Release Date: 2011-02-04
X Protocol Version 11, Revision 0
Build Operating System: Linux 2.6.37-gentoo-01 x86_64
Current Operating System: Linux mpc5125-twr 2.6.29.1 #1 PREEMPT Wed Apr
6 10:58:12 CEST 2011 ppc
Kernel command line: root=/dev/nfs rw
nfsroot=192.168.1.33:/MyOE/nfsroot/test01/mpc5125-twr-xfce46-image
console=ttyPSC0,115200
ip=192.168.1.8:192.168.1.33:192.168.1.1:255.255.255.0:ads5125:eth0:off
panic=1
Build Date: 06 April 2011 01:22:10PM
Current version of pixman: 0.21.6
Before reporting problems, check http://wiki.x.org
to make sure that you have the latest version.
Markers: (--) probed, (**) from config file, (==) default setting,
(++) from command line, (!!) notice, (II) informational,
(WW) warning, (EE) error, (NI) not implemented, (??) unknown.
(==) Log file: "/var/log/Xorg.0.log", Time: Wed Apr 6 12:52:01 2011
(==) Using config file: "/etc/X11/xorg.conf"
(==) Using system config directory "/usr/share/X11/xorg.conf.d"
(EE) Failed to load module "glx" (module does not exist, 0)
(EE) Failed to load module "dri" (module does not exist, 0)
(EE) Failed to load module "dri2" (module does not exist, 0)
Primary device is not PCI
(EE) USB Multimedia Keyboard : failed to initialize for relative axes.
/etc/xdg/xfce4/xinitrc: line 97: xrdb: not found
** (xfce4-session:1056): WARNING **: Unable to launch
"/usr/libexec/xfce4/xfconf-migration/xfconf-migration-4.6.pl" (specified
by autostart/xfconf-migration-4.6.desktop): Failed to execute child
process "/usr/libexec/xfce4/xfconf-migration/xfconf-migration-4.6.pl"
(No such file or directory)
** (xfsettingsd:1079): CRITICAL **: Failed to spawn xrdb: Failed to
execute child process "xrdb" (No such file or directory)
** (xfsettingsd:1079): CRITICAL **: Failed to spawn xrdb: Failed to
execute child process "xrdb" (No such file or directory)
xfdesktop[1070]: starting up
** (xfsettingsd:1079): CRITICAL **: Failed to spawn xrdb: Failed to
execute child process "xrdb" (No such file or directory)
** (xfsettingsd:1079): CRITICAL **: Failed to spawn xrdb: Failed to
execute child process "xrdb" (No such file or directory)
(Thunar:1068): thunar-vfs-WARNING **: Failed to connect to the HAL
daemon: Failed to connect to socket /var/run/dbus/system_bus_socket: No
such file or directory
** (xfsettingsd:1079): CRITICAL **: Failed to spawn xrdb: Failed to
execute child process "xrdb" (No such file or directory)
** (xfsettingsd:1079): CRITICAL **: Failed to spawn xrdb: Failed to
execute child process "xrdb" (No such file or directory)
(xfdesktop:1070): thunar-vfs-WARNING **: Failed to connect to the HAL
daemon: Failed to connect to socket /var/run/dbus/system_bus_socket: No
such file or directory
sh: fortune: not found
Gtk-Message: (for origin information, set GTK_DEBUG): failed to
retrieve property `GtkOptionMenu::indicator-size' of type
`GtkRequisition' from rc file value "0" of type `glong'
Gtk-Message: (for origin information, set GTK_DEBUG): failed to
retrieve property `GtkOptionMenu::indicator-spacing' of type `GtkBorder'
from rc file value "0" of type `glong'
vmstat
Output:
procs -----------memory---------- ---swap-- -----io---- -system--
----cpu----
r b swpd free buff cache si so bi bo in cs us sy
id wa
1 0 0 152576 0 61896 0 0 1 0 783 773 11 15
71 2
cat /proc/meminfo
Output:
MemTotal: 249408 kB
MemFree: 152576 kB
Buffers: 0 kB
Cached: 61896 kB
SwapCached: 0 kB
Active: 39156 kB
Inactive: 45132 kB
Active(anon): 24660 kB
Inactive(anon): 0 kB
Active(file): 14496 kB
Inactive(file): 45132 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 22440 kB
Mapped: 17832 kB
Slab: 8116 kB
SReclaimable: 4256 kB
SUnreclaim: 3860 kB
PageTables: 836 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 124704 kB
Committed_AS: 75076 kB
VmallocTotal: 737256 kB
VmallocUsed: 1560 kB
VmallocChunk: 734648 kB
ps aux
Output:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.4 0.2 1864 644 ? Ss 12:48 0:00 init [5]
root 2 0.0 0.0 0 0 ? S< 12:48 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S< 12:48 0:00
[ksoftirqd/0]
root 4 0.0 0.0 0 0 ? S< 12:48 0:00 [events/0]
root 5 0.0 0.0 0 0 ? S< 12:48 0:00 [khelper]
root 6 0.0 0.0 0 0 ? S< 12:48 0:00 [netns]
root 7 0.0 0.0 0 0 ? S< 12:48 0:00
[kintegrityd/0]
root 8 0.0 0.0 0 0 ? S< 12:48 0:00
[kblockd/0]
root 9 0.0 0.0 0 0 ? S< 12:48 0:00
[ksuspend_usbd]
root 10 0.0 0.0 0 0 ? S< 12:48 0:00 [khubd]
root 11 4.5 0.0 0 0 ? R< 12:48 0:10 [kmmcd]
root 12 0.0 0.0 0 0 ? S 12:48 0:00 [pdflush]
root 13 0.0 0.0 0 0 ? S 12:48 0:00 [pdflush]
root 14 0.0 0.0 0 0 ? S< 12:48 0:00 [kswapd0]
root 15 0.0 0.0 0 0 ? S< 12:48 0:00 [aio/0]
root 16 0.0 0.0 0 0 ? S< 12:48 0:00 [nfsiod]
root 21 0.0 0.0 0 0 ? S< 12:48 0:00
[mtdblockd]
root 22 0.0 0.0 0 0 ? S< 12:48 0:00
[hid_compat]
root 27 0.3 0.0 0 0 ? S< 12:48 0:00 [rpciod/0]
root 50 0.2 0.3 2668 896 ? S<s 12:49 0:00
/sbin/udevd -d
root 105 0.0 0.3 2664 944 ? S< 12:49 0:00
/sbin/udevd -d
root 107 0.0 0.3 2664 932 ? S< 12:49 0:00
/sbin/udevd -d
daemon 960 0.0 0.1 1852 412 ? Ss 12:49 0:00
/sbin/portmap
root 987 0.0 0.1 2512 496 ? Ss 12:49 0:00
/usr/sbin/dropbear -r /etc/dropbear/dropbear_rsa_host_key -p 22
root 990 0.1 1.1 11184 2860 ? Ss 12:49 0:00
/usr/sbin/smbd
root 992 0.0 0.6 6296 1536 ? Ss 12:49 0:00
/usr/sbin/nmbd
root 995 0.0 0.3 3420 776 ? Ss 12:49 0:00
/sbin/syslogd -n -C64 -m 20
root 997 0.0 0.2 3356 716 ? Ss 12:49 0:00
/sbin/klogd -n
root 1004 0.0 0.4 11184 1028 ? S 12:49 0:00
/usr/sbin/smbd
root 1027 0.3 0.3 2764 960 ? Ss 12:50 0:00
/usr/sbin/dropbear -r /etc/dropbear/dropbear_rsa_host_key -p 22
root 1028 0.0 0.4 3612 1020 pts/0 Ss 12:50 0:00 -sh
root 1036 0.0 0.3 3592 868 pts/0 S 12:52 0:00 xinit
/etc/xdg/xfce4/xinitrc
root 1037 10.2 3.9 24368 9812 tty2 S<s+ 12:52 0:05 X :0
root 1042 0.0 0.2 3360 748 pts/0 T 12:52 0:00 sh
/etc/xdg/xfce4/xinitrc
root 1053 0.0 0.3 4192 784 pts/0 T 12:52 0:00
/usr/bin/dbus-launch --sh-syntax --exit-with-session
root 1054 4.6 0.3 2892 864 ? Ss 12:52 0:02
/usr/bin/dbus-daemon --fork --print-pid 4 --print-address 7 --session
root 1056 1.3 2.4 20952 6132 pts/0 T 12:52 0:00
/usr/bin/xfce4-session
root 1058 4.0 0.8 4424 2016 ? S 12:52 0:02
/usr/libexec/xfconfd
root 1064 13.4 4.2 23764 10708 pts/0 T 12:52 0:06 xfwm4
root 1066 2.9 4.2 25480 10480 pts/0 T 12:52 0:01
xfce4-panel
root 1068 0.5 2.3 21484 5956 pts/0 T 12:52 0:00 Thunar
--daemon
root 1070 3.5 4.5 34768 11396 pts/0 T 12:52 0:01 xfdesktop
root 1079 0.5 1.5 19304 3844 pts/0 T 12:52 0:00
xfsettingsd
root 1081 0.2 0.5 3596 1444 ? S 12:52 0:00
/usr/libexec/gam_server
root 1095 0.6 1.5 20948 3816 ? S 12:52 0:00
xfce4-settings-helper
root 1097 1.9 3.3 23976 8232 pts/0 T 12:52 0:00
/usr/libexec/xfce4/panel-plugins/xfce4-menu-plugin socket_id 10485785
name xfce4-menu id 5 display_name Xfce Menu size 28 screen_position 11
root 1099 0.1 0.8 6252 2112 ? S 12:52 0:00
/usr/libexec/gvfsd
root 1103 0.0 1.0 31776 2548 ? Ssl 12:52 0:00
/usr/libexec//gvfs-fuse-daemon /home/root/.gvfs
root 1111 0.0 0.3 2668 992 pts/0 R+ 12:52 0:00 ps aux
Status
The GUI of Xfce appears on the screen and can be controlled by the mouse
and keyboard. A small black rectangle appears in the upper left corner of
the display. Several errors like missing group names are reported, when
booting, but the GUI appears and can be used. X server reports serveral
warnings but works. This is just a starting point for using xfce.
Unfortunately getty reports a Segmentation fault, when started. Therefore
login via the devices /dev/ttyPSC0 or /dev/tty1 is not possible. You can
login to the board with ssh via Ethernet.
Troubleshooting
Workaround when fetch fails
When you use the portage distfiles folder for downloads and bitbake fails
while fetching even when the file is there, this has helped usually:
sudo chmod -R g+w /usr/portage/distfiles
Start bitbake again.
Workaround for cannot stat error
When you start bitbake the current date is saved in some folder names.
When bitbake fails and you restart it on another day, the the folder
names
are different. You need to copy the files from the old folder to the new
folder like in this example and then start bitbake again: Output:
install: cannot stat
`/MyOE/tmp/test01/work/mpc5125-twr-angstrom-linux/angstrom-version-1_v20110406-r6/lsb_release':
No such file or directory
NOTE: package angstrom-version-1_v20110406-r6: task do_install: Failed
cd /MyOE/tmp/test01/work/mpc5125-twr-angstrom-linux;
cp angstrom-version-1_v20110406-r6/lsb_release
angstrom-version-1_v20110406-r6/
Bitbake Reports an Error
You are using the master branch of openembedded, which is constantly
changing. This is the latest version of openembedded. If the latest
version cannot be build, you can try to use the latest tested version.
Currently this is the version with the tag
021312cbea3bd07f2ec8591d667998c9c7b28b3a.
git status
Save all your changes, which you don't want to lose, before you continue.
Change to the tag 021312cbea3bd07f2ec8591d667998c9c7b28b3a.
git reflog;
git tag;
git reset 021312cbea3bd07f2ec8591d667998c9c7b28b3a;
Save and remove tracked files.
git stash save
Delete untracked files and directories dry-run
git clean -fdn
Delete untracked files and directories
git clean -fd
Check the current status.
git status;
git reflog;
Now install the patches for mpc5125-twr and try to build the images in an
empty directory $MY_TMP again.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT
2011-04-08 20:02 ` Jan Kobler
@ 2011-04-08 21:37 ` Tom Rini
2011-04-11 13:50 ` Jan Kobler
0 siblings, 1 reply; 8+ messages in thread
From: Tom Rini @ 2011-04-08 21:37 UTC (permalink / raw)
To: Jan Kobler; +Cc: openembedded-devel
On 04/08/2011 01:02 PM, Jan Kobler wrote:
> Hi,
>
> 1. I wanted to make a clear distinction between what I have written and
> what I have taken from
> http://www.freescale.com/files/soft_dev_tools/software/board_support_packages/TWRMPC5125LinuxBSP.rar
> which contains the Linux kernel 2.6.29-v2010041601 for the TWR-MPC5125-KIT.
>
> Therefore linux_VER.bb is in [mpc5125-twr 1/2], because I have changed
> it. Otherwise I would put it together in one patch.
>
> 2. I have tried to provide the same for Openembedded as Freescale is
> currently shipping on their web page
> http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=TWR-MPC5125-KIT&fpsp=1&tab=Design_Tools_Tab.
> I have not tried to port it to a more recent kernel.
>
> Is there already a more recent kernel, which contains mpc5125-twr support?
It's possible that yes, this hardware is supported in 2.6.37.
--
Tom Rini
Mentor Graphics Corporation
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: mpc5125-twr: Tutorial
2011-04-08 20:15 ` mpc5125-twr: Tutorial Jan Kobler
@ 2011-04-08 23:56 ` Jan Kobler
0 siblings, 0 replies; 8+ messages in thread
From: Jan Kobler @ 2011-04-08 23:56 UTC (permalink / raw)
To: openembedded-devel
Hi,
you can find the tutorial on gentoo-wiki.com now:
http://en.gentoo-wiki.com/wiki/Freescale_TWR-MPC5125/Openembedded
It describes the usage and the current state of the BSP for the new
machine mpc5125-twr.
I hope it helps.
Best regards
Jan
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT
2011-04-08 21:37 ` Tom Rini
@ 2011-04-11 13:50 ` Jan Kobler
0 siblings, 0 replies; 8+ messages in thread
From: Jan Kobler @ 2011-04-11 13:50 UTC (permalink / raw)
To: openembedded-devel
on 08.04.2011 23:37 Tom Rini said the following:
> On 04/08/2011 01:02 PM, Jan Kobler wrote:
>> 2. I have tried to provide the same for Openembedded as Freescale is
>> currently shipping on their web page
>> http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=TWR-MPC5125-KIT&fpsp=1&tab=Design_Tools_Tab.
>> I have not tried to port it to a more recent kernel.
>>
>> Is there already a more recent kernel, which contains mpc5125-twr support?
>
> It's possible that yes, this hardware is supported in 2.6.37.
>
The support in 2.6.37 seems to be for the CPU Freescale MPC5121 and the
board ADS512101. The support files for MPC5125 and TWR-MPC5125 are
missing. The names TWR-MPC5125 or "mpc5125-twr are nowhere mentioned.
E.g linux-2.6.29/arch/powerpc/boot/dts/mpc5125-twr.dts is missing in
linux-2.6.37
linux-2.6.37/arch/powerpc/boot/dts/mpc5121ads.dts is different to
linux-2.6.29/arch/powerpc/boot/dts/mpc5125-twr.dts
The CPUs MPC5125 and MPC5121 are similar, but are not the same.
Currently I don't know the exact differences and cannot decide which
code for MPC5121 runs also on MPC5125.
Best regards
Jan
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2011-04-11 13:58 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-04-08 19:33 [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT Jan Kobler
2011-04-08 19:33 ` [mpc5125-twr 2/2] Linux kernel for mpc5125-twr Jan Kobler
2011-04-08 19:43 ` [mpc5125-twr 1/2] New machine mpc5125-twr, Freescale TWR-MPC5125-KIT Tom Rini
2011-04-08 20:02 ` Jan Kobler
2011-04-08 21:37 ` Tom Rini
2011-04-11 13:50 ` Jan Kobler
2011-04-08 20:15 ` mpc5125-twr: Tutorial Jan Kobler
2011-04-08 23:56 ` Jan Kobler
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.