Browse Source

add support for m68k toolchain/qemu

Waldemar Brodkorb 12 years ago
parent
commit
86cb648cb7

+ 2 - 1
Config.in

@@ -20,6 +20,7 @@ config ADK_CHOOSE_TARGET_SYSTEM
 	default y if ADK_CHOOSE_TARGET_SYSTEM_ARM
 	default y if ADK_CHOOSE_TARGET_SYSTEM_ARM
 	default y if ADK_CHOOSE_TARGET_SYSTEM_AVR32
 	default y if ADK_CHOOSE_TARGET_SYSTEM_AVR32
 	default y if ADK_CHOOSE_TARGET_SYSTEM_CRIS
 	default y if ADK_CHOOSE_TARGET_SYSTEM_CRIS
+	default y if ADK_CHOOSE_TARGET_SYSTEM_M68K
 	default y if ADK_CHOOSE_TARGET_SYSTEM_MIPS
 	default y if ADK_CHOOSE_TARGET_SYSTEM_MIPS
 	default y if ADK_CHOOSE_TARGET_SYSTEM_PPC
 	default y if ADK_CHOOSE_TARGET_SYSTEM_PPC
 	default y if ADK_CHOOSE_TARGET_SYSTEM_PPC64
 	default y if ADK_CHOOSE_TARGET_SYSTEM_PPC64
@@ -94,7 +95,7 @@ prompt "Kernel Version"
 depends on ADK_TOOLCHAIN_ONLY
 depends on ADK_TOOLCHAIN_ONLY
 
 
 config ADK_KERNEL_VERSION_TOOLCHAIN
 config ADK_KERNEL_VERSION_TOOLCHAIN
-	prompt "2.6.39.4"
+	prompt "3.4.4"
 	boolean
 	boolean
 	depends on ADK_TOOLCHAIN_ONLY
 	depends on ADK_TOOLCHAIN_ONLY
 
 

+ 1 - 1
mk/kernel-build.mk

@@ -28,7 +28,7 @@ $(LINUX_DIR)/.config: $(LINUX_DIR)/.prepared $(BUILD_DIR)/.kernelconfig $(TOPDIR
 $(LINUX_DIR)/vmlinux: $(LINUX_DIR)/.config
 $(LINUX_DIR)/vmlinux: $(LINUX_DIR)/.config
 	-rm $(LINUX_DIR)/vmlinux
 	-rm $(LINUX_DIR)/vmlinux
 	$(TRACE) target/$(ADK_TARGET_ARCH)-kernel-compile
 	$(TRACE) target/$(ADK_TARGET_ARCH)-kernel-compile
-	${KERNEL_MAKE_ENV} $(MAKE) ${KERNEL_MAKE_OPTS} -j${ADK_MAKE_JOBS} LOCALVERSION="" $(MAKE_TRACE)
+	${KERNEL_MAKE_ENV} $(MAKE) V=1 ${KERNEL_MAKE_OPTS} -j${ADK_MAKE_JOBS} LOCALVERSION="" $(MAKE_TRACE)
 	$(TRACE) target/$(ADK_TARGET_ARCH)-kernel-modules-install
 	$(TRACE) target/$(ADK_TARGET_ARCH)-kernel-modules-install
 	rm -rf $(LINUX_BUILD_DIR)/modules
 	rm -rf $(LINUX_BUILD_DIR)/modules
 	${KERNEL_MAKE_ENV} $(MAKE) ${KERNEL_MAKE_OPTS} DEPMOD=true \
 	${KERNEL_MAKE_ENV} $(MAKE) ${KERNEL_MAKE_OPTS} DEPMOD=true \

+ 2 - 2
mk/kernel-ver.mk

@@ -1,8 +1,8 @@
 ifeq ($(ADK_KERNEL_VERSION_TOOLCHAIN),y)
 ifeq ($(ADK_KERNEL_VERSION_TOOLCHAIN),y)
-KERNEL_VERSION:=	2.6.39.4
+KERNEL_VERSION:=	3.4.4
 KERNEL_MOD_VERSION:=	$(KERNEL_VERSION)
 KERNEL_MOD_VERSION:=	$(KERNEL_VERSION)
 KERNEL_RELEASE:=	1
 KERNEL_RELEASE:=	1
-KERNEL_MD5SUM:=		a17c748c2070168f1e784e9605ca043d
+KERNEL_MD5SUM:=		6b8420c24e6f25c56824ce085d194687
 endif
 endif
 ifeq ($(ADK_KERNEL_VERSION_2_6_39_4),y)
 ifeq ($(ADK_KERNEL_VERSION_2_6_39_4),y)
 KERNEL_VERSION:=	2.6.39.4
 KERNEL_VERSION:=	2.6.39.4

+ 1 - 0
target/arch.lst

@@ -1,6 +1,7 @@
 arm
 arm
 avr32
 avr32
 cris
 cris
+m68k
 mips
 mips
 ppc
 ppc
 ppc64
 ppc64

+ 4 - 0
target/config/Config.in

@@ -331,6 +331,9 @@ config ADK_CPU_ARMV5
 config ADK_CPU_XSCALE
 config ADK_CPU_XSCALE
 	boolean
 	boolean
 
 
+config ADK_CPU_M68K
+	boolean
+
 config ADK_TARGET_CPU_ARCH
 config ADK_TARGET_CPU_ARCH
 	string
 	string
 	default "x86_64" if ADK_CPU_X86_64
 	default "x86_64" if ADK_CPU_X86_64
@@ -341,6 +344,7 @@ config ADK_TARGET_CPU_ARCH
 	default "i586" if ADK_CPU_GEODE
 	default "i586" if ADK_CPU_GEODE
 	default "i686" if ADK_CPU_PENTIUM_M
 	default "i686" if ADK_CPU_PENTIUM_M
 	default "i686" if ADK_CPU_ATOM
 	default "i686" if ADK_CPU_ATOM
+	default "m68k" if ADK_LINUX_M68K
 	default "mips64" if ADK_LINUX_MIPS && ADK_big && ADK_TARGET_KERNEL64
 	default "mips64" if ADK_LINUX_MIPS && ADK_big && ADK_TARGET_KERNEL64
 	default "mips64el" if ADK_LINUX_MIPS && ADK_little && ADK_TARGET_KERNEL64
 	default "mips64el" if ADK_LINUX_MIPS && ADK_little && ADK_TARGET_KERNEL64
 	default "mips" if ADK_LINUX_MIPS && ADK_big
 	default "mips" if ADK_LINUX_MIPS && ADK_big

+ 6 - 0
target/config/Config.in.arch.choice

@@ -32,6 +32,12 @@ config ADK_LINUX_CRIS
 	help
 	help
 	  Support for CRIS systems.
 	  Support for CRIS systems.
 
 
+config ADK_LINUX_M68K
+	bool "m68k system"
+	select ADK_m68k
+	help
+	  Support for m68k systems.
+
 config ADK_LINUX_MIPS
 config ADK_LINUX_MIPS
 	bool "mips system"
 	bool "mips system"
 	select ADK_mips
 	select ADK_mips

+ 4 - 0
target/config/Config.in.arch.default

@@ -14,6 +14,9 @@ config ADK_avr32
 config ADK_cris
 config ADK_cris
 	bool
 	bool
 
 
+config ADK_m68k
+	bool
+
 config ADK_mips
 config ADK_mips
 	bool
 	bool
 
 
@@ -53,6 +56,7 @@ config ADK_TARGET_ARCH
 	default "arm"  if ADK_armeb
 	default "arm"  if ADK_armeb
 	default "avr32"  if ADK_avr32
 	default "avr32"  if ADK_avr32
 	default "cris"  if ADK_cris
 	default "cris"  if ADK_cris
+	default "m68k"  if ADK_m68k
 	default "mips"  if ADK_mips
 	default "mips"  if ADK_mips
 	default "mips"  if ADK_mipsel
 	default "mips"  if ADK_mipsel
 	default "mips"  if ADK_mips64
 	default "mips"  if ADK_mips64

+ 1 - 0
target/config/Config.in.system.choice

@@ -1,6 +1,7 @@
 source "target/arm/Config.in"
 source "target/arm/Config.in"
 source "target/avr32/Config.in"
 source "target/avr32/Config.in"
 source "target/cris/Config.in"
 source "target/cris/Config.in"
+source "target/m68k/Config.in"
 source "target/mips/Config.in"
 source "target/mips/Config.in"
 source "target/ppc/Config.in"
 source "target/ppc/Config.in"
 source "target/ppc64/Config.in"
 source "target/ppc64/Config.in"

+ 1 - 1
target/linux/config/Config.in.netfilter

@@ -2,7 +2,7 @@ menu "Netfilter (Firewall/Filtering)"
 
 
 config ADK_KERNEL_NETFILTER
 config ADK_KERNEL_NETFILTER
 	bool
 	bool
-	default y
+	default n
 
 
 config ADK_KERNEL_NETFILTER_ADVANCED
 config ADK_KERNEL_NETFILTER_ADVANCED
 	bool
 	bool

+ 1 - 1
target/linux/config/Config.in.network

@@ -158,7 +158,7 @@ config ADK_KPACKAGE_KMOD_NET_IPGRE
 config ADK_KPACKAGE_KMOD_IPV6
 config ADK_KPACKAGE_KMOD_IPV6
 	prompt "kmod-ipv6......................... IPv6 support"
 	prompt "kmod-ipv6......................... IPv6 support"
 	tristate
 	tristate
-	default m
+	default m if !ADK_LINUX_M68K
 	help
 	help
 	  This is complemental support for the IP version 6.
 	  This is complemental support for the IP version 6.
 	  You will still be able to do traditional IPv4 networking as well.
 	  You will still be able to do traditional IPv4 networking as well.

+ 9 - 0
target/m68k/Config.in

@@ -0,0 +1,9 @@
+choice
+depends on ADK_LINUX_M68K && !ADK_CHOOSE_TARGET_ARCH
+prompt "Target system"
+
+config ADK_CHOOSE_TARGET_SYSTEM_M68K
+	boolean "Choose target system"
+
+source "target/m68k/Config.in.systems"
+endchoice

+ 42 - 0
target/m68k/Makefile

@@ -0,0 +1,42 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+include $(TOPDIR)/rules.mk
+include $(TOPDIR)/mk/kernel.mk
+include $(TOPDIR)/mk/modules.mk
+include $(TOPDIR)/mk/kernel-build.mk
+include $(TOPDIR)/mk/image.mk
+
+KERNEL:=$(LINUX_DIR)/vmlinux
+
+ifeq ($(ADK_TARGET_FS),archive)
+imageinstall: $(BIN_DIR)/$(ROOTFSTARBALL)
+	@cp $(KERNEL) $(BIN_DIR)/$(TARGET_KERNEL)
+	@echo 'The kernel file is: $(BIN_DIR)/${TARGET_KERNEL}'
+	@echo "The RootFS tarball is: $(BIN_DIR)/$(ROOTFSTARBALL)"
+ifeq ($(ADK_TARGET_SYSTEM_QEMU_M68K),y)
+	@echo "Use following command to create a QEMU Image:"
+	@echo "sudo ./scripts/create-image.sh -f ${ADK_TARGET_ROOTFS} qemu-${CPU_ARCH}.img $(BIN_DIR)/$(ROOTFSTARBALL)"
+	@echo "Start qemu with following command line:"
+	@echo 'qemu-system-m68k -nographic -kernel $(BIN_DIR)/$(TARGET_KERNEL) qemu-${CPU_ARCH}.img'
+endif
+endif
+ifeq ($(ADK_TARGET_FS),initramfs)
+imageinstall: $(BIN_DIR)/$(INITRAMFS)
+	@cp $(KERNEL) $(BIN_DIR)/$(TARGET_KERNEL)
+	@echo 'The kernel file is: $(BIN_DIR)/${TARGET_KERNEL}'
+	@echo 'The initramfs image is: ${BIN_DIR}/${INITRAMFS}'
+ifeq ($(ADK_TARGET_SYSTEM_QEMU_M68K),y)
+	@echo "Start qemu with following command line:"
+	@echo 'qemu-system-m68k -nographic -kernel $(BIN_DIR)/$(TARGET_KERNEL) -initrd ${BIN_DIR}/${INITRAMFS}'
+endif
+endif
+ifeq ($(ADK_TARGET_FS),initramfs-piggyback)
+imageinstall: createinitramfs
+	@cp $(KERNEL) $(BIN_DIR)/${TARGET_KERNEL}
+	@echo 'The kernel+initramfs file is: $(BIN_DIR)/${TARGET_KERNEL}'
+ifeq ($(ADK_TARGET_SYSTEM_QEMU_M68K),y)
+	@echo "Start qemu with following command line:"
+	@echo 'qemu-system-m68k -nographic -kernel $(BIN_DIR)/$(TARGET_KERNEL)'
+endif
+endif

+ 878 - 0
target/m68k/kernel.config

@@ -0,0 +1,878 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/m68k 3.4.4 Kernel Configuration
+#
+CONFIG_M68K=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_TIME_LOW_RES=y
+CONFIG_ARCH_USES_GETTIMEOFFSET=y
+CONFIG_NO_IOPORT=y
+# CONFIG_NO_DMA is not set
+CONFIG_ZONE_DMA=y
+CONFIG_CPU_HAS_ADDRESS_SPACES=y
+CONFIG_FPU=y
+CONFIG_HZ=100
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_FHANDLE is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_SHOW=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TINY_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EXPERT is not set
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=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_EMBEDDED is not set
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_PROFILING is not set
+
+#
+# GCOV-based kernel profiling
+#
+# 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 is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+# CONFIG_FREEZER is not set
+CONFIG_MMU=y
+CONFIG_MMU_MOTOROLA=y
+
+#
+# Platform setup
+#
+
+#
+# Processor Type
+#
+CONFIG_M68KCLASSIC=y
+# CONFIG_COLDFIRE is not set
+CONFIG_M68020=y
+# CONFIG_M68030 is not set
+# CONFIG_M68040 is not set
+# CONFIG_M68060 is not set
+
+#
+# Processor Specific Options
+#
+# CONFIG_M68KFPU_EMU is not set
+# CONFIG_ADVANCED is not set
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_M68K_L2_CACHE=y
+CONFIG_NODES_SHIFT=3
+
+#
+# Machine Types
+#
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+CONFIG_MAC=y
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+
+#
+# Bus Support
+#
+CONFIG_NUBUS=y
+# CONFIG_GENERIC_ISA_DMA is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# Kernel Features
+#
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_DISCONTIGMEM_MANUAL=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION 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_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_NEED_PER_CPU_KM=y
+# CONFIG_CLEANCACHE is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+CONFIG_BQL=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+CONFIG_NET_9P=y
+# CONFIG_NET_9P_DEBUG is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_DEVTMPFS=y
+# CONFIG_DEVTMPFS_MOUNT is not set
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_GENERIC_CPU_DEVICES=y
+# CONFIG_DMA_SHARED_BUFFER is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_SWIM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_RBD is not set
+
+#
+# Misc devices
+#
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+
+#
+# Altera FPGA firmware download module
+#
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+CONFIG_IDE_ATAPI=y
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_PROC_FS is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_PLATFORM is not set
+CONFIG_BLK_DEV_MAC_IDE=y
+# CONFIG_BLK_DEV_IDEDMA is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# 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 is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_MAC_SCSI=y
+CONFIG_SCSI_MAC_ESP=y
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_MD is not set
+# CONFIG_TARGET_CORE is not set
+CONFIG_MACINTOSH_DRIVERS=y
+CONFIG_ADB=y
+CONFIG_ADB_MACII=y
+# CONFIG_ADB_MACIISI is not set
+# CONFIG_ADB_IOP is not set
+# CONFIG_ADB_PMU68K is not set
+# CONFIG_ADB_CUDA is not set
+# CONFIG_INPUT_ADBHID is not set
+# CONFIG_MAC_EMUMOUSEBTN is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_CORE is not set
+
+#
+# CAIF transport drivers
+#
+CONFIG_ETHERNET=y
+# CONFIG_NET_VENDOR_APPLE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_CALXEDA_XGMAC is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_DNET is not set
+CONFIG_NET_VENDOR_INTEL=y
+# CONFIG_NET_VENDOR_I825XX is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+CONFIG_NET_VENDOR_NATSEMI=y
+# CONFIG_MACSONIC is not set
+CONFIG_NET_VENDOR_8390=y
+CONFIG_MAC8390=y
+# CONFIG_ETHOC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_PHYLIB is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+# CONFIG_TRACE_SINK is not set
+# CONFIG_DEVKMEM is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_PMACZILOG=y
+CONFIG_SERIAL_PMACZILOG_TTYS=y
+CONFIG_SERIAL_PMACZILOG_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_HSI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+
+#
+# Enable Device Drivers -> PPS to see the PTP clock options.
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_EXYNOS_VIDEO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB_ARCH_HAS_XHCI is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY 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 is not set
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# 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_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_GENERIC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_BALLOON is not set
+# CONFIG_VIRTIO_MMIO is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+# CONFIG_STAGING is not set
+
+#
+# Hardware Spinlock drivers
+#
+# CONFIG_IOMMU_SUPPORT is not set
+
+#
+# Remoteproc drivers (EXPERIMENTAL)
+#
+
+#
+# Rpmsg drivers (EXPERIMENTAL)
+#
+# CONFIG_VIRT_DRIVERS is not set
+# CONFIG_PM_DEVFREQ is not set
+
+#
+# Platform devices
+#
+CONFIG_PROC_HARDWARE=y
+
+#
+# Character devices
+#
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+# CONFIG_EXT4_FS_XATTR is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+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_LOGFS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_XATTR is not set
+CONFIG_SQUASHFS_ZLIB=y
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_XZ is not set
+# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_MINIX_FS_BIG_ENDIAN_16BIT_INDEXED is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+CONFIG_9P_FS=y
+CONFIG_9P_FS_POSIX_ACL=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_BOOTPARAM is not set
+CONFIG_EARLY_PRINTK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+# CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IO=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_CRC8 is not set
+CONFIG_ZLIB_INFLATE=y
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_DMA=y
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set

+ 5713 - 0
target/m68k/patches/cris.patch

@@ -0,0 +1,5713 @@
+diff -Nur linux-2.6.36.orig/arch/cris/Kconfig linux-2.6.36/arch/cris/Kconfig
+--- linux-2.6.36.orig/arch/cris/Kconfig	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/Kconfig	2010-11-15 17:57:17.000000000 +0100
+@@ -177,6 +177,12 @@
+ 	help
+ 	  Size of DRAM (decimal in MB) typically 2, 8 or 16.
+ 
++config ETRAX_MTD_SIZE
++	hex "MTD size (hex)"
++	default "0x00800000"
++	help
++	  Size of MTD device typically 4 or 8 MB.
++
+ config ETRAX_VMEM_SIZE
+        int "Video memory size (dec, in MB)"
+        depends on ETRAX_ARCH_V32 && !ETRAXFS
+@@ -282,7 +288,7 @@
+ 	select MTD_CFI_AMDSTD
+ 	select MTD_JEDECPROBE if ETRAX_ARCH_V32
+ 	select MTD_CHAR
+-	select MTD_BLOCK
++	select MTD_BLOCK_RO
+ 	select MTD_PARTITIONS
+ 	select MTD_CONCAT
+ 	select MTD_COMPLEX_MAPPINGS
+@@ -671,6 +677,11 @@
+ 
+ source "drivers/ide/Kconfig"
+ 
++#mysteriously part of this standard linux driver was removed from cris build! - info@crisos.org  
++source "drivers/scsi/Kconfig"
++
++source "drivers/media/Kconfig"
++
+ source "drivers/net/Kconfig"
+ 
+ source "drivers/i2c/Kconfig"
+diff -Nur linux-2.6.36.orig/arch/cris/Makefile linux-2.6.36/arch/cris/Makefile
+--- linux-2.6.36.orig/arch/cris/Makefile	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/Makefile	2010-11-15 17:57:17.000000000 +0100
+@@ -40,10 +40,10 @@
+ 
+ LD = $(CROSS_COMPILE)ld -mcrislinux
+ 
+-OBJCOPYFLAGS := -O binary -R .note -R .comment -S
++OBJCOPYFLAGS := -O binary -R .bss -R .note -R .note.gnu.build-id -R .comment -S
+ 
+ KBUILD_AFLAGS += -mlinux -march=$(arch-y) $(inc)
+-KBUILD_CFLAGS += -mlinux -march=$(arch-y) -pipe $(inc)
++KBUILD_CFLAGS += -mlinux -march=$(arch-y) -pipe -fno-peephole2 $(inc)
+ KBUILD_CPPFLAGS += $(inc)
+ 
+ ifdef CONFIG_FRAME_POINTER
+diff -Nur linux-2.6.36.orig/arch/cris/arch-v10/drivers/axisflashmap.c linux-2.6.36/arch/cris/arch-v10/drivers/axisflashmap.c
+--- linux-2.6.36.orig/arch/cris/arch-v10/drivers/axisflashmap.c	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/arch-v10/drivers/axisflashmap.c	2010-11-15 17:57:17.000000000 +0100
+@@ -113,7 +113,7 @@
+ 
+ /* If no partition-table was found, we use this default-set. */
+ #define MAX_PARTITIONS         7
+-#define NUM_DEFAULT_PARTITIONS 3
++#define NUM_DEFAULT_PARTITIONS 4
+ 
+ /*
+  * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
+@@ -122,19 +122,24 @@
+  */
+ static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = {
+ 	{
+-		.name = "boot firmware",
+-		.size = CONFIG_ETRAX_PTABLE_SECTOR,
++		.name = "kernel",
++		.size = 0x00,
+ 		.offset = 0
+ 	},
+ 	{
+-		.name = "kernel",
+-		.size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR),
+-		.offset = CONFIG_ETRAX_PTABLE_SECTOR
++		.name = "rootfs",
++		.size = 0x200000 ,
++		.offset = 0x200000
+ 	},
+ 	{
+-		.name = "filesystem",
+-		.size = 5 * CONFIG_ETRAX_PTABLE_SECTOR,
+-		.offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR)
++		.name = "cfgfs",
++		.size = 0x20000 ,
++		.offset = CONFIG_ETRAX_MTD_SIZE - 0x20000
++	},
++	{
++		.name = "linux",
++		.size = CONFIG_ETRAX_MTD_SIZE - 0x20000,
++		.offset = 0
+ 	}
+ };
+ 
+@@ -281,6 +286,11 @@
+ 	struct partitiontable_entry *ptable;
+ 	int use_default_ptable = 1; /* Until proven otherwise. */
+ 	const char pmsg[] = "  /dev/flash%d at 0x%08x, size 0x%08x\n";
++	unsigned int kernel_part_size = 0;
++	unsigned char *flash_mem = (unsigned char*)(FLASH_CACHED_ADDR);
++	unsigned int flash_scan_count = 0;
++	const char *part_magic = "ACME_PART_MAGIC";
++	unsigned int magic_len = strlen(part_magic);
+ 
+ 	if (!(mymtd = flash_probe())) {
+ 		/* There's no reason to use this module if no flash chip can
+@@ -292,6 +302,31 @@
+ 		       mymtd->name, mymtd->size);
+ 		axisflash_mtd = mymtd;
+ 	}
++	/* scan flash to findout where out partition starts */
++
++	printk(KERN_INFO "Scanning flash for end of kernel magic\n");
++	for(flash_scan_count = 0; flash_scan_count < 100000; flash_scan_count++){
++		if(strncmp(&flash_mem[flash_scan_count], part_magic, magic_len - 1) == 0)
++		{
++			kernel_part_size = flash_mem[flash_scan_count + magic_len ];
++			kernel_part_size <<= 8;
++			kernel_part_size += flash_mem[flash_scan_count + magic_len + 2];
++			kernel_part_size <<= 8;
++			kernel_part_size += flash_mem[flash_scan_count + magic_len + 1];
++			kernel_part_size <<= 8;
++			kernel_part_size += flash_mem[flash_scan_count + magic_len + 3];
++			printk(KERN_INFO "Kernel ends at 0x%.08X\n", kernel_part_size);
++			flash_scan_count = 1100000;
++		}
++	}
++
++
++	if(kernel_part_size){
++		kernel_part_size = (kernel_part_size & 0xffff0000);
++		axis_default_partitions[0].size = kernel_part_size;
++		axis_default_partitions[1].size =  mymtd->size - axis_default_partitions[0].size - axis_default_partitions[2].size;
++		axis_default_partitions[1].offset = axis_default_partitions[0].size;
++	}
+ 
+ 	if (mymtd) {
+ 		mymtd->owner = THIS_MODULE;
+@@ -360,21 +395,6 @@
+ 		use_default_ptable = !ptable_ok;
+ 	}
+ 
+-	if (romfs_in_flash) {
+-		/* Add an overlapping device for the root partition (romfs). */
+-
+-		axis_partitions[pidx].name = "romfs";
+-		axis_partitions[pidx].size = romfs_length;
+-		axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
+-		axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
+-
+-		printk(KERN_INFO
+-                       " Adding readonly flash partition for romfs image:\n");
+-		printk(pmsg, pidx, axis_partitions[pidx].offset,
+-		       axis_partitions[pidx].size);
+-		pidx++;
+-	}
+-
+ #ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
+ 	if (mymtd) {
+ 		main_partition.size = mymtd->size;
+@@ -397,36 +417,6 @@
+ 		if (err)
+ 			panic("axisflashmap could not add MTD partitions!\n");
+ 	}
+-
+-	if (!romfs_in_flash) {
+-		/* Create an RAM device for the root partition (romfs). */
+-
+-#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
+-		/* No use trying to boot this kernel from RAM. Panic! */
+-		printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
+-		       "device due to kernel (mis)configuration!\n");
+-		panic("This kernel cannot boot from RAM!\n");
+-#else
+-		struct mtd_info *mtd_ram;
+-
+-		mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+-		if (!mtd_ram)
+-			panic("axisflashmap couldn't allocate memory for "
+-			      "mtd_info!\n");
+-
+-		printk(KERN_INFO " Adding RAM partition for romfs image:\n");
+-		printk(pmsg, pidx, (unsigned)romfs_start,
+-			(unsigned)romfs_length);
+-
+-		err = mtdram_init_device(mtd_ram,
+-			(void *)romfs_start,
+-			romfs_length,
+-			"romfs");
+-		if (err)
+-			panic("axisflashmap could not initialize MTD RAM "
+-			      "device!\n");
+-#endif
+-	}
+ 	return err;
+ }
+ 
+diff -Nur linux-2.6.36.orig/arch/cris/arch-v10/drivers/ds1302.c linux-2.6.36/arch/cris/arch-v10/drivers/ds1302.c
+--- linux-2.6.36.orig/arch/cris/arch-v10/drivers/ds1302.c	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/arch-v10/drivers/ds1302.c	2010-11-15 17:57:17.000000000 +0100
+@@ -22,6 +22,7 @@
+ #include <linux/smp_lock.h>
+ #include <linux/bcd.h>
+ #include <linux/capability.h>
++#include <linux/device.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+@@ -499,6 +500,10 @@
+ 	return 0;
+ }
+ 
++#ifdef CONFIG_SYSFS
++static struct class *rtc_class;
++#endif
++
+ static int __init ds1302_register(void)
+ {
+ 	ds1302_init();
+@@ -507,6 +512,12 @@
+ 		       ds1302_name, RTC_MAJOR_NR);
+ 		return -1;
+ 	}
++	#ifdef CONFIG_SYSFS
++	rtc_class = class_create(THIS_MODULE, "rtc");
++	class_device_create(rtc_class, NULL, MKDEV(RTC_MAJOR_NR, 0),
++		NULL, "rtc");
++	#endif
++
+         return 0;
+ 
+ }
+diff -Nur linux-2.6.36.orig/arch/cris/arch-v10/drivers/gpio.c linux-2.6.36/arch/cris/arch-v10/drivers/gpio.c
+--- linux-2.6.36.orig/arch/cris/arch-v10/drivers/gpio.c	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/arch-v10/drivers/gpio.c	2010-11-15 17:57:17.000000000 +0100
+@@ -20,6 +20,7 @@
+ #include <linux/poll.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
++#include <linux/device.h>
+ 
+ #include <asm/etraxgpio.h>
+ #include <arch/svinto.h>
+@@ -797,6 +798,10 @@
+ 
+ /* main driver initialization routine, called from mem.c */
+ 
++#ifdef CONFIG_SYSFS
++static struct class *gpio_class;
++#endif
++
+ static int __init gpio_init(void)
+ {
+ 	int res;
+@@ -810,6 +815,13 @@
+ 		return res;
+ 	}
+ 
++#ifdef CONFIG_SYSFS
++	gpio_class = class_create(THIS_MODULE, "gpio");
++	device_create(gpio_class, NULL, MKDEV(GPIO_MAJOR, 0), NULL, "gpioa");
++	device_create(gpio_class, NULL, MKDEV(GPIO_MAJOR, 1), NULL, "gpiob");
++	device_create(gpio_class, NULL, MKDEV(GPIO_MAJOR, 2), NULL, "leds");
++	device_create(gpio_class, NULL, MKDEV(GPIO_MAJOR, 3), NULL, "gpiog");
++#endif
+ 	/* Clear all leds */
+ #if defined (CONFIG_ETRAX_CSP0_LEDS) ||  defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS)
+ 	CRIS_LED_NETWORK_SET(0);
+diff -Nur linux-2.6.36.orig/arch/cris/arch-v10/lib/hw_settings.S linux-2.6.36/arch/cris/arch-v10/lib/hw_settings.S
+--- linux-2.6.36.orig/arch/cris/arch-v10/lib/hw_settings.S	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/arch-v10/lib/hw_settings.S	2010-11-15 17:57:17.000000000 +0100
+@@ -58,3 +58,5 @@
+ 	.dword R_PORT_PB_SET
+ 	.dword PB_SET_VALUE
+ 	.dword 0 ; No more register values
++	.ascii "ACME_PART_MAGIC" 
++	.dword 0xdeadc0de
+diff -Nur linux-2.6.36.orig/arch/cris/arch-v10/mm/init.c linux-2.6.36/arch/cris/arch-v10/mm/init.c
+--- linux-2.6.36.orig/arch/cris/arch-v10/mm/init.c	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/arch-v10/mm/init.c	2010-11-15 17:57:17.000000000 +0100
+@@ -184,6 +184,9 @@
+ 
+ 	free_area_init_node(0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0);
+ }
++void free_initrd_mem(unsigned long start, unsigned long end)
++{
++}
+ 
+ /* Initialize remaps of some I/O-ports. It is important that this
+  * is called before any driver is initialized.
+diff -Nur linux-2.6.36.orig/arch/cris/boot/Makefile linux-2.6.36/arch/cris/boot/Makefile
+--- linux-2.6.36.orig/arch/cris/boot/Makefile	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/boot/Makefile	2010-11-15 17:57:17.000000000 +0100
+@@ -5,7 +5,7 @@
+ objcopyflags-$(CONFIG_ETRAX_ARCH_V10) += -R .note -R .comment
+ objcopyflags-$(CONFIG_ETRAX_ARCH_V32) += --remove-section=.bss --remove-section=.note.gnu.build-id
+ 
+-OBJCOPYFLAGS = -O binary $(objcopyflags-y)
++#OBJCOPYFLAGS = -O binary $(objcopyflags-y)
+ 
+ 
+ subdir- := compressed rescue
+@@ -17,7 +17,6 @@
+ 
+ $(obj)/compressed/vmlinux: $(obj)/Image FORCE
+ 	$(Q)$(MAKE) $(build)=$(obj)/compressed $@
+-	$(Q)$(MAKE) $(build)=$(obj)/rescue $(obj)/rescue/rescue.bin
+ 
+ $(obj)/zImage:  $(obj)/compressed/vmlinux
+ 	@cp $< $@
+diff -Nur linux-2.6.36.orig/arch/cris/boot/compressed/Makefile linux-2.6.36/arch/cris/boot/compressed/Makefile
+--- linux-2.6.36.orig/arch/cris/boot/compressed/Makefile	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/arch/cris/boot/compressed/Makefile	2010-11-15 17:57:17.000000000 +0100
+@@ -18,7 +18,7 @@
+ OBJECTS-$(CONFIG_ETRAX_ARCH_V32) = $(obj)/head_v32.o
+ OBJECTS-$(CONFIG_ETRAX_ARCH_V10) = $(obj)/head_v10.o
+ OBJECTS= $(OBJECTS-y) $(obj)/misc.o
+-OBJCOPYFLAGS = -O binary --remove-section=.bss
++#OBJCOPYFLAGS = -O binary --remove-section=.bss
+ 
+ quiet_cmd_image = BUILD   $@
+ cmd_image = cat $(obj)/decompress.bin $(obj)/piggy.gz > $@
+diff -Nur linux-2.6.36.orig/drivers/net/cris/eth_v10.c linux-2.6.36/drivers/net/cris/eth_v10.c
+--- linux-2.6.36.orig/drivers/net/cris/eth_v10.c	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/net/cris/eth_v10.c	2010-11-15 17:57:17.000000000 +0100
+@@ -1718,7 +1718,7 @@
+ static void
+ e100_netpoll(struct net_device* netdev)
+ {
+-	e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev, NULL);
++	e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev);
+ }
+ #endif
+ 
+diff -Nur linux-2.6.36.orig/drivers/serial/crisv10.c linux-2.6.36/drivers/serial/crisv10.c
+--- linux-2.6.36.orig/drivers/serial/crisv10.c	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/serial/crisv10.c	2010-11-15 17:57:17.000000000 +0100
+@@ -13,6 +13,7 @@
+ #include <linux/errno.h>
+ #include <linux/signal.h>
+ #include <linux/sched.h>
++#include <linux/smp_lock.h> 
+ #include <linux/timer.h>
+ #include <linux/interrupt.h>
+ #include <linux/tty.h>
+@@ -27,6 +28,7 @@
+ #include <linux/kernel.h>
+ #include <linux/mutex.h>
+ #include <linux/bitops.h>
++#include <linux/device.h>
+ #include <linux/seq_file.h>
+ #include <linux/delay.h>
+ #include <linux/module.h>
+@@ -4426,6 +4428,7 @@
+ #endif
+ };
+ 
++static struct class *rs_class;
+ static int __init rs_init(void)
+ {
+ 	int i;
+@@ -4559,6 +4562,24 @@
+ #endif
+ #endif /* CONFIG_SVINTO_SIM */
+ 
++	rs_class = class_create(THIS_MODULE, "rs_tty");
++#ifdef CONFIG_ETRAX_SERIAL_PORT0 
++	device_create(rs_class, NULL,
++		MKDEV(TTY_MAJOR, 64), NULL, "ttyS0");
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT1 
++	device_create(rs_class, NULL,
++		MKDEV(TTY_MAJOR, 65), NULL, "ttyS1");
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT2 
++	device_create(rs_class, NULL,
++		MKDEV(TTY_MAJOR, 66), NULL, "ttyS2");
++#endif
++#ifdef CONFIG_ETRAX_SERIAL_PORT3 
++	device_create(rs_class, NULL,
++		MKDEV(TTY_MAJOR, 67), NULL, "ttyS3");
++#endif
++
+ 	return 0;
+ }
+ 
+diff -Nur linux-2.6.36.orig/drivers/usb/Makefile linux-2.6.36/drivers/usb/Makefile
+--- linux-2.6.36.orig/drivers/usb/Makefile	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/usb/Makefile	2010-11-15 17:57:18.000000000 +0100
+@@ -21,6 +21,7 @@
+ obj-$(CONFIG_USB_R8A66597_HCD)	+= host/
+ obj-$(CONFIG_USB_HWA_HCD)	+= host/
+ obj-$(CONFIG_USB_ISP1760_HCD)	+= host/
++obj-$(CONFIG_ETRAX_USB_HOST)	+= host/
+ obj-$(CONFIG_USB_IMX21_HCD)	+= host/
+ 
+ obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00/
+diff -Nur linux-2.6.36.orig/drivers/usb/host/Makefile linux-2.6.36/drivers/usb/host/Makefile
+--- linux-2.6.36.orig/drivers/usb/host/Makefile	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/drivers/usb/host/Makefile	2010-11-15 17:57:18.000000000 +0100
+@@ -32,5 +32,6 @@
+ obj-$(CONFIG_USB_R8A66597_HCD)	+= r8a66597-hcd.o
+ obj-$(CONFIG_USB_ISP1760_HCD)	+= isp1760.o
+ obj-$(CONFIG_USB_HWA_HCD)	+= hwa-hc.o
++obj-$(CONFIG_ETRAX_USB_HOST)	+= hc-crisv10.o
+ obj-$(CONFIG_USB_IMX21_HCD)	+= imx21-hcd.o
+ 
+diff -Nur linux-2.6.36.orig/drivers/usb/host/hc-cris-dbg.h linux-2.6.36/drivers/usb/host/hc-cris-dbg.h
+--- linux-2.6.36.orig/drivers/usb/host/hc-cris-dbg.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/drivers/usb/host/hc-cris-dbg.h	2010-11-15 17:57:17.000000000 +0100
+@@ -0,0 +1,146 @@
++
++/* macros for debug output */
++
++#define warn(fmt, args...) \
++        printk(KERN_INFO "crisv10 warn: ");printk(fmt, ## args)
++
++#define hcd_dbg(hcd, fmt, args...) \
++	dev_info(hcd->self.controller, fmt, ## args)
++#define hcd_err(hcd, fmt, args...) \
++	dev_err(hcd->self.controller, fmt, ## args)
++#define hcd_info(hcd, fmt, args...) \
++	dev_info(hcd->self.controller, fmt, ## args)
++#define hcd_warn(hcd, fmt, args...) \
++	dev_warn(hcd->self.controller, fmt, ## args)
++
++/*
++#define devdrv_dbg(fmt, args...) \
++        printk(KERN_INFO "usb_devdrv dbg: ");printk(fmt, ## args)
++*/
++#define devdrv_dbg(fmt, args...) {}
++
++#define devdrv_err(fmt, args...) \
++        printk(KERN_ERR "usb_devdrv error: ");printk(fmt, ## args)
++#define devdrv_info(fmt, args...) \
++        printk(KERN_INFO "usb_devdrv: ");printk(fmt, ## args)
++
++#define irq_dbg(fmt, args...) \
++        printk(KERN_INFO "crisv10_irq dbg: ");printk(fmt, ## args)
++#define irq_err(fmt, args...) \
++        printk(KERN_ERR "crisv10_irq error: ");printk(fmt, ## args)
++#define irq_warn(fmt, args...) \
++        printk(KERN_INFO "crisv10_irq warn: ");printk(fmt, ## args)
++#define irq_info(fmt, args...) \
++        printk(KERN_INFO "crisv10_hcd: ");printk(fmt, ## args)
++
++/*
++#define rh_dbg(fmt, args...) \
++  printk(KERN_DEBUG "crisv10_rh dbg: ");printk(fmt, ## args)
++*/
++#define rh_dbg(fmt, args...) {}
++
++#define rh_err(fmt, args...) \
++        printk(KERN_ERR "crisv10_rh error: ");printk(fmt, ## args)
++#define rh_warn(fmt, args...) \
++        printk(KERN_INFO "crisv10_rh warning: ");printk(fmt, ## args)
++#define rh_info(fmt, args...) \
++        printk(KERN_INFO "crisv10_rh: ");printk(fmt, ## args)
++
++/*
++#define tc_dbg(fmt, args...) \
++        printk(KERN_INFO "crisv10_tc dbg: ");printk(fmt, ## args)
++*/
++#define tc_dbg(fmt, args...) {while(0){}}
++
++#define tc_err(fmt, args...) \
++        printk(KERN_ERR "crisv10_tc error: ");printk(fmt, ## args)
++/*
++#define tc_warn(fmt, args...) \
++        printk(KERN_INFO "crisv10_tc warning: ");printk(fmt, ## args)
++*/
++#define tc_warn(fmt, args...) {while(0){}}
++
++#define tc_info(fmt, args...) \
++        printk(KERN_INFO "crisv10_tc: ");printk(fmt, ## args)
++
++
++/* Debug print-outs for various traffic types */
++
++#define intr_warn(fmt, args...) \
++        printk(KERN_INFO "crisv10_intr warning: ");printk(fmt, ## args)
++
++#define intr_dbg(fmt, args...) \
++        printk(KERN_DEBUG "crisv10_intr dbg: ");printk(fmt, ## args)
++/*
++#define intr_dbg(fmt, args...) {while(0){}}
++*/
++
++
++#define isoc_err(fmt, args...) \
++        printk(KERN_ERR "crisv10_isoc error: ");printk(fmt, ## args)
++/*
++#define isoc_warn(fmt, args...) \
++        printk(KERN_INFO "crisv10_isoc warning: ");printk(fmt, ## args)
++*/
++#define isoc_warn(fmt, args...) {while(0){}}
++
++/*
++#define isoc_dbg(fmt, args...) \
++        printk(KERN_INFO "crisv10_isoc dbg: ");printk(fmt, ## args)
++*/
++#define isoc_dbg(fmt, args...) {while(0){}}
++
++/*
++#define timer_warn(fmt, args...) \
++        printk(KERN_INFO "crisv10_timer warning: ");printk(fmt, ## args)
++*/
++#define timer_warn(fmt, args...) {while(0){}}
++
++/*
++#define timer_dbg(fmt, args...) \
++        printk(KERN_INFO "crisv10_timer dbg: ");printk(fmt, ## args)
++*/
++#define timer_dbg(fmt, args...) {while(0){}}
++
++
++/* Debug printouts for events related to late finishing of URBs */
++
++#define late_dbg(fmt, args...) \
++        printk(KERN_INFO "crisv10_late dbg: ");printk(fmt, ## args)
++/*
++#define late_dbg(fmt, args...) {while(0){}}
++*/
++
++#define late_warn(fmt, args...) \
++        printk(KERN_INFO "crisv10_late warning: ");printk(fmt, ## args)
++/*
++#define errno_dbg(fmt, args...) \
++        printk(KERN_INFO "crisv10_errno dbg: ");printk(fmt, ## args)
++*/
++#define errno_dbg(fmt, args...) {while(0){}}
++
++
++#define dma_dbg(fmt, args...) \
++        printk(KERN_INFO "crisv10_dma dbg: ");printk(fmt, ## args)
++#define dma_err(fmt, args...) \
++        printk(KERN_ERR "crisv10_dma error: ");printk(fmt, ## args)
++#define dma_warn(fmt, args...) \
++        printk(KERN_INFO "crisv10_dma warning: ");printk(fmt, ## args)
++#define dma_info(fmt, args...) \
++        printk(KERN_INFO "crisv10_dma: ");printk(fmt, ## args)
++
++
++
++#define str_dir(pipe) \
++	(usb_pipeout(pipe) ? "out" : "in")
++#define str_type(pipe) \
++	({								\
++		char *s = "?";						\
++		switch (usb_pipetype(pipe)) {				\
++		case PIPE_ISOCHRONOUS:	s = "iso";  break;		\
++		case PIPE_INTERRUPT:	s = "intr"; break;		\
++		case PIPE_CONTROL:	s = "ctrl"; break;		\
++		case PIPE_BULK:		s = "bulk"; break;		\
++		};							\
++		s;							\
++	})
+diff -Nur linux-2.6.36.orig/drivers/usb/host/hc-crisv10.c linux-2.6.36/drivers/usb/host/hc-crisv10.c
+--- linux-2.6.36.orig/drivers/usb/host/hc-crisv10.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/drivers/usb/host/hc-crisv10.c	2010-11-15 17:57:18.000000000 +0100
+@@ -0,0 +1,4801 @@
++/*
++ *
++ * ETRAX 100LX USB Host Controller Driver
++ *
++ * Copyright (C) 2005, 2006  Axis Communications AB
++ *
++ * Author: Konrad Eriksson <konrad.eriksson@axis.se>
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/moduleparam.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/usb.h>
++#include <linux/platform_device.h>
++#include <linux/usb/hcd.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <arch/dma.h>
++#include <arch/io_interface_mux.h>
++
++#include "hc-crisv10.h"
++#include "hc-cris-dbg.h"
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* Host Controller settings                                                */
++/***************************************************************************/
++/***************************************************************************/
++
++#define VERSION			"1.00 hinko.4"
++#define COPYRIGHT		"(c) 2005, 2006 Axis Communications AB"
++#define DESCRIPTION     "ETRAX 100LX USB Host Controller"
++
++#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR
++#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR
++#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR
++
++/* Number of physical ports in Etrax 100LX */
++#define USB_ROOT_HUB_PORTS 2
++
++const char hc_name[] = "hc-crisv10";
++const char product_desc[] = DESCRIPTION;
++
++/* The number of epids is, among other things, used for pre-allocating
++   ctrl, bulk and isoc EP descriptors (one for each epid).
++   Assumed to be > 1 when initiating the DMA lists. */
++#define NBR_OF_EPIDS       32
++
++/* Support interrupt traffic intervals up to 128 ms. */
++#define MAX_INTR_INTERVAL  128
++
++/* If periodic traffic (intr or isoc) is to be used, then one entry in the EP
++   table must be "invalid". By this we mean that we shouldn't care about epid
++   attentions for this epid, or at least handle them differently from epid
++   attentions for "valid" epids. This define determines which one to use
++   (don't change it). */
++#define INVALID_EPID       31
++/* A special epid for the bulk dummys. */
++#define DUMMY_EPID         30
++
++/* Module settings */
++
++MODULE_DESCRIPTION(DESCRIPTION);
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Konrad Eriksson <konrad.eriksson@axis.se>");
++
++
++/* Module parameters */
++
++/* 0 = No ports enabled
++   1 = Only port 1 enabled (on board ethernet on devboard)
++   2 = Only port 2 enabled (external connector on devboard)
++   3 = Both ports enabled
++*/
++static unsigned int ports = 3;
++module_param(ports, uint, S_IRUGO);
++MODULE_PARM_DESC(ports, "Bitmask indicating USB ports to use");
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* Shared global variables for this module                                 */
++/***************************************************************************/
++/***************************************************************************/
++
++/* EP descriptor lists for non period transfers. Must be 32-bit aligned. */
++static volatile struct USB_EP_Desc TxBulkEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
++
++static volatile struct USB_EP_Desc TxCtrlEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
++
++/* EP descriptor lists for period transfers. Must be 32-bit aligned. */
++static volatile struct USB_EP_Desc TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
++static volatile struct USB_SB_Desc TxIntrSB_zout __attribute__ ((aligned (4)));
++
++static volatile struct USB_EP_Desc TxIsocEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
++static volatile struct USB_SB_Desc TxIsocSB_zout __attribute__ ((aligned (4)));
++
++//static volatile struct USB_SB_Desc TxIsocSBList[NBR_OF_EPIDS] __attribute__ ((aligned (4))); 
++
++/* After each enabled bulk EP IN we put two disabled EP descriptors with the eol flag set,
++   causing the DMA to stop the DMA channel. The first of these two has the intr flag set, which
++   gives us a dma8_sub0_descr interrupt. When we receive this, we advance the DMA one step in the
++   EP list and then restart the bulk channel, thus forcing a switch between bulk EP descriptors
++   in each frame. */
++static volatile struct USB_EP_Desc TxBulkDummyEPList[NBR_OF_EPIDS][2] __attribute__ ((aligned (4)));
++
++/* List of URB pointers, where each points to the active URB for a epid.
++   For Bulk, Ctrl and Intr this means which URB that currently is added to
++   DMA lists (Isoc URBs are all directly added to DMA lists). As soon as
++   URB has completed is the queue examined and the first URB in queue is
++   removed and moved to the activeUrbList while its state change to STARTED and
++   its transfer(s) gets added to DMA list (exception Isoc where URBs enter
++   state STARTED directly and added transfers added to DMA lists). */
++static struct urb *activeUrbList[NBR_OF_EPIDS];
++
++/* Additional software state info for each epid */
++static struct etrax_epid epid_state[NBR_OF_EPIDS];
++
++/* Timer handles for bulk traffic timer used to avoid DMA bug where DMA stops
++   even if there is new data waiting to be processed */
++static struct timer_list bulk_start_timer = TIMER_INITIALIZER(NULL, 0, 0);
++static struct timer_list bulk_eot_timer = TIMER_INITIALIZER(NULL, 0, 0);
++
++/* We want the start timer to expire before the eot timer, because the former
++   might start traffic, thus making it unnecessary for the latter to time
++   out. */
++#define BULK_START_TIMER_INTERVAL (HZ/50) /* 20 ms */
++#define BULK_EOT_TIMER_INTERVAL (HZ/16) /* 60 ms */
++
++/* Delay before a URB completion happen when it's scheduled to be delayed */
++#define LATER_TIMER_DELAY (HZ/50) /* 20 ms */
++
++/* Simplifying macros for checking software state info of a epid */
++/* ----------------------------------------------------------------------- */
++#define epid_inuse(epid)       epid_state[epid].inuse
++#define epid_out_traffic(epid) epid_state[epid].out_traffic
++#define epid_isoc(epid)   (epid_state[epid].type == PIPE_ISOCHRONOUS ? 1 : 0)
++#define epid_intr(epid)   (epid_state[epid].type == PIPE_INTERRUPT ? 1 : 0)
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* DEBUG FUNCTIONS                                                         */
++/***************************************************************************/
++/***************************************************************************/
++/* Note that these functions are always available in their "__" variants,
++   for use in error situations. The "__" missing variants are controlled by
++   the USB_DEBUG_DESC/USB_DEBUG_URB macros. */
++static void __dump_urb(struct urb* purb)
++{
++  struct crisv10_urb_priv *urb_priv = purb->hcpriv;
++  int urb_num = -1;
++  if(urb_priv) {
++    urb_num = urb_priv->urb_num;
++  }
++  printk("\nURB:0x%x[%d]\n", (unsigned int)purb, urb_num);
++  printk("dev                   :0x%08lx\n", (unsigned long)purb->dev);
++  printk("pipe                  :0x%08x\n", purb->pipe);
++  printk("status                :%d\n", purb->status);
++  printk("transfer_flags        :0x%08x\n", purb->transfer_flags);
++  printk("transfer_buffer       :0x%08lx\n", (unsigned long)purb->transfer_buffer);
++  printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
++  printk("actual_length         :%d\n", purb->actual_length);
++  printk("setup_packet          :0x%08lx\n", (unsigned long)purb->setup_packet);
++  printk("start_frame           :%d\n", purb->start_frame);
++  printk("number_of_packets     :%d\n", purb->number_of_packets);
++  printk("interval              :%d\n", purb->interval);
++  printk("error_count           :%d\n", purb->error_count);
++  printk("context               :0x%08lx\n", (unsigned long)purb->context);
++  printk("complete              :0x%08lx\n\n", (unsigned long)purb->complete);
++}
++
++static void __dump_in_desc(volatile struct USB_IN_Desc *in)
++{
++  printk("\nUSB_IN_Desc at 0x%08lx\n", (unsigned long)in);
++  printk("  sw_len  : 0x%04x (%d)\n", in->sw_len, in->sw_len);
++  printk("  command : 0x%04x\n", in->command);
++  printk("  next    : 0x%08lx\n", in->next);
++  printk("  buf     : 0x%08lx\n", in->buf);
++  printk("  hw_len  : 0x%04x (%d)\n", in->hw_len, in->hw_len);
++  printk("  status  : 0x%04x\n\n", in->status);
++}
++
++static void __dump_sb_desc(volatile struct USB_SB_Desc *sb)
++{
++  char tt = (sb->command & 0x30) >> 4;
++  char *tt_string;
++
++  switch (tt) {
++  case 0:
++    tt_string = "zout";
++    break;
++  case 1:
++    tt_string = "in";
++    break;
++  case 2:
++    tt_string = "out";
++    break;
++  case 3:
++    tt_string = "setup";
++    break;
++  default:
++    tt_string = "unknown (weird)";
++  }
++
++  printk(" USB_SB_Desc at 0x%08lx ", (unsigned long)sb);
++  printk(" command:0x%04x (", sb->command);
++  printk("rem:%d ", (sb->command & 0x3f00) >> 8);
++  printk("full:%d ", (sb->command & 0x40) >> 6);
++  printk("tt:%d(%s) ", tt, tt_string);
++  printk("intr:%d ", (sb->command & 0x8) >> 3);
++  printk("eot:%d ", (sb->command & 0x2) >> 1);
++  printk("eol:%d)", sb->command & 0x1);
++  printk(" sw_len:0x%04x(%d)", sb->sw_len, sb->sw_len);
++  printk(" next:0x%08lx", sb->next);
++  printk(" buf:0x%08lx\n", sb->buf);
++}
++
++
++static void __dump_ep_desc(volatile struct USB_EP_Desc *ep)
++{
++  printk("USB_EP_Desc at 0x%08lx ", (unsigned long)ep);
++  printk(" command:0x%04x (", ep->command);
++  printk("ep_id:%d ", (ep->command & 0x1f00) >> 8);
++  printk("enable:%d ", (ep->command & 0x10) >> 4);
++  printk("intr:%d ", (ep->command & 0x8) >> 3);
++  printk("eof:%d ", (ep->command & 0x2) >> 1);
++  printk("eol:%d)", ep->command & 0x1);
++  printk(" hw_len:0x%04x(%d)", ep->hw_len, ep->hw_len);
++  printk(" next:0x%08lx", ep->next);
++  printk(" sub:0x%08lx\n", ep->sub);
++}
++
++static inline void __dump_ep_list(int pipe_type)
++{
++  volatile struct USB_EP_Desc *ep;
++  volatile struct USB_EP_Desc *first_ep;
++  volatile struct USB_SB_Desc *sb;
++
++  switch (pipe_type)
++    {
++    case PIPE_BULK:
++      first_ep = &TxBulkEPList[0];
++      break;
++    case PIPE_CONTROL:
++      first_ep = &TxCtrlEPList[0];
++      break;
++    case PIPE_INTERRUPT:
++      first_ep = &TxIntrEPList[0];
++      break;
++    case PIPE_ISOCHRONOUS:
++      first_ep = &TxIsocEPList[0];
++      break;
++    default:
++      warn("Cannot dump unknown traffic type");
++      return;
++    }
++  ep = first_ep;
++
++  printk("\n\nDumping EP list...\n\n");
++
++  do {
++    __dump_ep_desc(ep);
++    /* Cannot phys_to_virt on 0 as it turns into 80000000, which is != 0. */
++    sb = ep->sub ? phys_to_virt(ep->sub) : 0;
++    while (sb) {
++      __dump_sb_desc(sb);
++      sb = sb->next ? phys_to_virt(sb->next) : 0;
++    }
++    ep = (volatile struct USB_EP_Desc *)(phys_to_virt(ep->next));
++
++  } while (ep != first_ep);
++}
++
++static inline void __dump_ept_data(int epid)
++{
++  unsigned long flags;
++  __u32 r_usb_ept_data;
++
++  if (epid < 0 || epid > 31) {
++    printk("Cannot dump ept data for invalid epid %d\n", epid);
++    return;
++  }
++
++  local_irq_save(flags);
++  *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
++  nop();
++  r_usb_ept_data = *R_USB_EPT_DATA;
++  local_irq_restore(flags);
++
++  printk(" R_USB_EPT_DATA = 0x%x for epid %d :\n", r_usb_ept_data, epid);
++  if (r_usb_ept_data == 0) {
++    /* No need for more detailed printing. */
++    return;
++  }
++  printk("  valid           : %d\n", (r_usb_ept_data & 0x80000000) >> 31);
++  printk("  hold            : %d\n", (r_usb_ept_data & 0x40000000) >> 30);
++  printk("  error_count_in  : %d\n", (r_usb_ept_data & 0x30000000) >> 28);
++  printk("  t_in            : %d\n", (r_usb_ept_data & 0x08000000) >> 27);
++  printk("  low_speed       : %d\n", (r_usb_ept_data & 0x04000000) >> 26);
++  printk("  port            : %d\n", (r_usb_ept_data & 0x03000000) >> 24);
++  printk("  error_code      : %d\n", (r_usb_ept_data & 0x00c00000) >> 22);
++  printk("  t_out           : %d\n", (r_usb_ept_data & 0x00200000) >> 21);
++  printk("  error_count_out : %d\n", (r_usb_ept_data & 0x00180000) >> 19);
++  printk("  max_len         : %d\n", (r_usb_ept_data & 0x0003f800) >> 11);
++  printk("  ep              : %d\n", (r_usb_ept_data & 0x00000780) >> 7);
++  printk("  dev             : %d\n", (r_usb_ept_data & 0x0000003f));
++}
++
++static inline void __dump_ept_data_iso(int epid)
++{
++  unsigned long flags;
++  __u32 ept_data;
++
++  if (epid < 0 || epid > 31) {
++    printk("Cannot dump ept data for invalid epid %d\n", epid);
++    return;
++  }
++
++  local_irq_save(flags);
++  *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
++  nop();
++  ept_data = *R_USB_EPT_DATA_ISO;
++  local_irq_restore(flags);
++
++  printk(" R_USB_EPT_DATA = 0x%x for epid %d :\n", ept_data, epid);
++  if (ept_data == 0) {
++    /* No need for more detailed printing. */
++    return;
++  }
++  printk("  valid           : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, valid,
++						ept_data));
++  printk("  port            : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, port,
++						ept_data));
++  printk("  error_code      : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code,
++						ept_data));
++  printk("  max_len         : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len,
++						ept_data));
++  printk("  ep              : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, ep,
++						ept_data));
++  printk("  dev             : %d\n", IO_EXTRACT(R_USB_EPT_DATA_ISO, dev,
++						ept_data));
++}
++
++static inline void __dump_ept_data_list(void)
++{
++  int i;
++
++  printk("Dumping the whole R_USB_EPT_DATA list\n");
++
++  for (i = 0; i < 32; i++) {
++    __dump_ept_data(i);
++  }
++}
++
++static void debug_epid(int epid) {
++  int i;
++  
++  if(epid_isoc(epid)) {
++    __dump_ept_data_iso(epid);
++  } else {
++    __dump_ept_data(epid);
++  }
++
++  printk("Bulk:\n");
++  for(i = 0; i < 32; i++) {
++    if(IO_EXTRACT(USB_EP_command, epid, TxBulkEPList[i].command) ==
++       epid) {
++      printk("%d: ", i); __dump_ep_desc(&(TxBulkEPList[i]));
++    }
++  }
++
++  printk("Ctrl:\n");
++  for(i = 0; i < 32; i++) {
++    if(IO_EXTRACT(USB_EP_command, epid, TxCtrlEPList[i].command) ==
++       epid) {
++      printk("%d: ", i); __dump_ep_desc(&(TxCtrlEPList[i]));
++    }
++  }
++
++  printk("Intr:\n");
++  for(i = 0; i < MAX_INTR_INTERVAL; i++) {
++    if(IO_EXTRACT(USB_EP_command, epid, TxIntrEPList[i].command) ==
++       epid) {
++      printk("%d: ", i); __dump_ep_desc(&(TxIntrEPList[i]));
++    }
++  }
++  
++  printk("Isoc:\n");
++  for(i = 0; i < 32; i++) {
++    if(IO_EXTRACT(USB_EP_command, epid, TxIsocEPList[i].command) ==
++       epid) {
++      printk("%d: ", i); __dump_ep_desc(&(TxIsocEPList[i]));
++    }
++  }
++
++  __dump_ept_data_list();
++  __dump_ep_list(PIPE_INTERRUPT);
++  printk("\n\n");
++}
++
++
++
++char* hcd_status_to_str(__u8 bUsbStatus) {
++  static char hcd_status_str[128];
++  hcd_status_str[0] = '\0';
++  if(bUsbStatus & IO_STATE(R_USB_STATUS, ourun, yes)) {
++    strcat(hcd_status_str, "ourun ");
++  }
++  if(bUsbStatus & IO_STATE(R_USB_STATUS, perror, yes)) {
++    strcat(hcd_status_str, "perror ");
++  }
++  if(bUsbStatus & IO_STATE(R_USB_STATUS, device_mode, yes)) {
++    strcat(hcd_status_str, "device_mode ");
++  }
++  if(bUsbStatus & IO_STATE(R_USB_STATUS, host_mode, yes)) {
++    strcat(hcd_status_str, "host_mode ");
++  }
++  if(bUsbStatus & IO_STATE(R_USB_STATUS, started, yes)) {
++    strcat(hcd_status_str, "started ");
++  }
++  if(bUsbStatus & IO_STATE(R_USB_STATUS, running, yes)) {
++    strcat(hcd_status_str, "running ");
++  }
++  return hcd_status_str;
++}
++
++
++char* sblist_to_str(struct USB_SB_Desc* sb_desc) {
++  static char sblist_to_str_buff[128];
++  char tmp[32], tmp2[32];
++  sblist_to_str_buff[0] = '\0';
++  while(sb_desc != NULL) {
++    switch(IO_EXTRACT(USB_SB_command, tt, sb_desc->command)) {
++    case 0: sprintf(tmp, "zout");  break;
++    case 1: sprintf(tmp, "in");    break;
++    case 2: sprintf(tmp, "out");   break;
++    case 3: sprintf(tmp, "setup"); break;
++    }
++    sprintf(tmp2, "(%s %d)", tmp, sb_desc->sw_len);
++    strcat(sblist_to_str_buff, tmp2);
++    if(sb_desc->next != 0) {
++      sb_desc = phys_to_virt(sb_desc->next);
++    } else {
++      sb_desc = NULL;
++    }
++  }
++  return sblist_to_str_buff;
++}
++
++char* port_status_to_str(__u16 wPortStatus) {
++  static char port_status_str[128];
++  port_status_str[0] = '\0';
++  if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) {
++    strcat(port_status_str, "connected ");
++  }
++  if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)) {
++    strcat(port_status_str, "enabled ");
++  }
++  if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, suspended, yes)) {
++    strcat(port_status_str, "suspended ");
++  }
++  if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, reset, yes)) {
++    strcat(port_status_str, "reset ");
++  }
++  if(wPortStatus & IO_STATE(R_USB_RH_PORT_STATUS_1, speed, full)) {
++    strcat(port_status_str, "full-speed ");
++  } else {
++    strcat(port_status_str, "low-speed ");
++  }
++  return port_status_str;
++}
++
++
++char* endpoint_to_str(struct usb_endpoint_descriptor *ed) {
++  static char endpoint_to_str_buff[128];
++  char tmp[32];
++  int epnum = ed->bEndpointAddress & 0x0F;
++  int dir = ed->bEndpointAddress & 0x80;
++  int type = ed->bmAttributes & 0x03;
++  endpoint_to_str_buff[0] = '\0';
++  sprintf(endpoint_to_str_buff, "ep:%d ", epnum);
++  switch(type) {
++  case 0:
++    sprintf(tmp, " ctrl");
++    break;
++  case 1:
++    sprintf(tmp, " isoc");
++    break;
++  case 2:
++    sprintf(tmp, " bulk");
++    break;
++  case 3:
++    sprintf(tmp, " intr");
++    break;
++  }
++  strcat(endpoint_to_str_buff, tmp);
++  if(dir) {
++    sprintf(tmp, " in");
++  } else {
++    sprintf(tmp, " out");
++  }
++  strcat(endpoint_to_str_buff, tmp);
++
++  return endpoint_to_str_buff;
++}
++
++/* Debug helper functions for Transfer Controller */
++char* pipe_to_str(unsigned int pipe) {
++  static char pipe_to_str_buff[128];
++  char tmp[64];
++  sprintf(pipe_to_str_buff, "dir:%s", str_dir(pipe));
++  sprintf(tmp, " type:%s", str_type(pipe));
++  strcat(pipe_to_str_buff, tmp);
++
++  sprintf(tmp, " dev:%d", usb_pipedevice(pipe));
++  strcat(pipe_to_str_buff, tmp);
++  sprintf(tmp, " ep:%d", usb_pipeendpoint(pipe));
++  strcat(pipe_to_str_buff, tmp);
++  return pipe_to_str_buff;
++}
++
++
++#define USB_DEBUG_DESC 1
++
++#ifdef USB_DEBUG_DESC
++#define dump_in_desc(x) __dump_in_desc(x)
++#define dump_sb_desc(...) __dump_sb_desc(...)
++#define dump_ep_desc(x) __dump_ep_desc(x)
++#define dump_ept_data(x) __dump_ept_data(x)
++#else
++#define dump_in_desc(...) do {} while (0)
++#define dump_sb_desc(...) do {} while (0)
++#define dump_ep_desc(...) do {} while (0)
++#endif
++
++
++/* Uncomment this to enable massive function call trace
++   #define USB_DEBUG_TRACE */
++//#define USB_DEBUG_TRACE 1
++
++#ifdef USB_DEBUG_TRACE
++#define DBFENTER (printk(": Entering: %s\n", __FUNCTION__))
++#define DBFEXIT  (printk(": Exiting:  %s\n", __FUNCTION__))
++#else
++#define DBFENTER do {} while (0)
++#define DBFEXIT  do {} while (0)
++#endif
++
++#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \
++{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);}
++
++/* Most helpful debugging aid */
++#define ASSERT(expr) ((void) ((expr) ? 0 : (err("assert failed at: %s %d",__FUNCTION__, __LINE__))))
++
++
++/***************************************************************************/
++/***************************************************************************/
++/* Forward declarations                                                    */
++/***************************************************************************/
++/***************************************************************************/
++void crisv10_hcd_epid_attn_irq(struct crisv10_irq_reg *reg);
++void crisv10_hcd_port_status_irq(struct crisv10_irq_reg *reg);
++void crisv10_hcd_ctl_status_irq(struct crisv10_irq_reg *reg);
++void crisv10_hcd_isoc_eof_irq(struct crisv10_irq_reg *reg);
++
++void rh_port_status_change(__u16[]);
++int  rh_clear_port_feature(__u8, __u16);
++int  rh_set_port_feature(__u8, __u16);
++static void rh_disable_port(unsigned int port);
++
++static void check_finished_bulk_tx_epids(struct usb_hcd *hcd,
++					 int timer);
++
++//static int  tc_setup_epid(struct usb_host_endpoint *ep, struct urb *urb,
++//			 int mem_flags);
++static int tc_setup_epid(struct urb *urb, int mem_flags);
++static void tc_free_epid(struct usb_host_endpoint *ep);
++static int  tc_allocate_epid(void);
++static void tc_finish_urb(struct usb_hcd *hcd, struct urb *urb, int status);
++static void tc_finish_urb_later(struct usb_hcd *hcd, struct urb *urb,
++				int status);
++
++static int  urb_priv_create(struct usb_hcd *hcd, struct urb *urb, int epid,
++			   int mem_flags);
++static void urb_priv_free(struct usb_hcd *hcd, struct urb *urb);
++
++static inline struct urb *urb_list_first(int epid);
++static inline void        urb_list_add(struct urb *urb, int epid,
++				      int mem_flags);
++static inline urb_entry_t *urb_list_entry(struct urb *urb, int epid);
++static inline void        urb_list_del(struct urb *urb, int epid);
++static inline void        urb_list_move_last(struct urb *urb, int epid);
++static inline struct urb *urb_list_next(struct urb *urb, int epid);
++
++int create_sb_for_urb(struct urb *urb, int mem_flags);
++int init_intr_urb(struct urb *urb, int mem_flags);
++
++static inline void  etrax_epid_set(__u8 index, __u32 data);
++static inline void  etrax_epid_clear_error(__u8 index);
++static inline void  etrax_epid_set_toggle(__u8 index, __u8 dirout,
++					      __u8 toggle);
++static inline __u8  etrax_epid_get_toggle(__u8 index, __u8 dirout);
++static inline __u32 etrax_epid_get(__u8 index);
++
++/* We're accessing the same register position in Etrax so
++   when we do full access the internal difference doesn't matter */
++#define etrax_epid_iso_set(index, data) etrax_epid_set(index, data)
++#define etrax_epid_iso_get(index) etrax_epid_get(index)
++
++
++//static void        tc_dma_process_isoc_urb(struct urb *urb);
++static void        tc_dma_process_queue(int epid);
++static void        tc_dma_unlink_intr_urb(struct urb *urb);
++static irqreturn_t tc_dma_tx_interrupt(int irq, void *vhc);
++static irqreturn_t tc_dma_rx_interrupt(int irq, void *vhc);
++
++static void tc_bulk_start_timer_func(unsigned long dummy);
++static void tc_bulk_eot_timer_func(unsigned long dummy);
++
++
++/*************************************************************/
++/*************************************************************/
++/* Host Controler Driver block                               */
++/*************************************************************/
++/*************************************************************/
++
++/* HCD operations */
++static irqreturn_t crisv10_hcd_top_irq(int irq, void*);
++static int crisv10_hcd_reset(struct usb_hcd *);
++static int crisv10_hcd_start(struct usb_hcd *);
++static void crisv10_hcd_stop(struct usb_hcd *);
++#ifdef CONFIG_PM
++static int crisv10_hcd_suspend(struct device *, u32, u32);
++static int crisv10_hcd_resume(struct device *, u32);
++#endif /* CONFIG_PM */
++static int crisv10_hcd_get_frame(struct usb_hcd *);
++
++//static int  tc_urb_enqueue(struct usb_hcd *, struct usb_host_endpoint *ep, struct urb *, gfp_t mem_flags);
++static int tc_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
++//static int  tc_urb_dequeue(struct usb_hcd *, struct urb *);
++static int tc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
++static void tc_endpoint_disable(struct usb_hcd *, struct usb_host_endpoint *ep);
++
++static int rh_status_data_request(struct usb_hcd *, char *);
++static int rh_control_request(struct usb_hcd *, u16, u16, u16, char*, u16);
++
++#ifdef CONFIG_PM
++static int crisv10_hcd_hub_suspend(struct usb_hcd *);
++static int crisv10_hcd_hub_resume(struct usb_hcd *);
++#endif /* CONFIG_PM */
++#ifdef CONFIG_USB_OTG
++static int crisv10_hcd_start_port_reset(struct usb_hcd *, unsigned);
++#endif /* CONFIG_USB_OTG */
++
++/* host controller driver interface */
++static const struct hc_driver crisv10_hc_driver = 
++  {
++    .description =	hc_name,
++    .product_desc =	product_desc,
++    .hcd_priv_size =	sizeof(struct crisv10_hcd),
++
++    /* Attaching IRQ handler manualy in probe() */
++    /* .irq =		crisv10_hcd_irq, */
++
++    .flags =		HCD_USB11,
++
++    /* called to init HCD and root hub */
++    .reset =		crisv10_hcd_reset,
++    .start =		crisv10_hcd_start,	
++
++    /* cleanly make HCD stop writing memory and doing I/O */
++    .stop =		crisv10_hcd_stop,
++
++    /* return current frame number */
++    .get_frame_number =	crisv10_hcd_get_frame,
++
++
++    /* Manage i/o requests via the Transfer Controller */
++    .urb_enqueue =	tc_urb_enqueue,
++    .urb_dequeue =	tc_urb_dequeue,
++
++    /* hw synch, freeing endpoint resources that urb_dequeue can't */
++    .endpoint_disable = tc_endpoint_disable,
++
++
++    /* Root Hub support */
++    .hub_status_data =	rh_status_data_request,
++    .hub_control =	rh_control_request,
++#ifdef CONFIG_PM
++    .hub_suspend =	rh_suspend_request,
++    .hub_resume =	rh_resume_request,
++#endif /* CONFIG_PM */
++#ifdef	CONFIG_USB_OTG
++    .start_port_reset =	crisv10_hcd_start_port_reset,
++#endif /* CONFIG_USB_OTG */
++  };
++
++
++/*
++ * conversion between pointers to a hcd and the corresponding
++ * crisv10_hcd 
++ */
++
++static inline struct crisv10_hcd *hcd_to_crisv10_hcd(struct usb_hcd *hcd)
++{
++	return (struct crisv10_hcd *) hcd->hcd_priv;
++}
++
++static inline struct usb_hcd *crisv10_hcd_to_hcd(struct crisv10_hcd *hcd)
++{
++	return container_of((void *) hcd, struct usb_hcd, hcd_priv);
++}
++
++/* check if specified port is in use */
++static inline int port_in_use(unsigned int port)
++{
++	return ports & (1 << port);
++}
++
++/* number of ports in use */
++static inline unsigned int num_ports(void)
++{
++	unsigned int i, num = 0;
++	for (i = 0; i < USB_ROOT_HUB_PORTS; i++)
++		if (port_in_use(i))
++			num++;
++	return num;
++}
++
++/* map hub port number to the port number used internally by the HC */
++static inline unsigned int map_port(unsigned int port)
++{
++  unsigned int i, num = 0;
++  for (i = 0; i < USB_ROOT_HUB_PORTS; i++)
++    if (port_in_use(i))
++      if (++num == port)
++	return i;
++  return -1;
++}
++
++/* size of descriptors in slab cache */
++#ifndef MAX
++#define MAX(x, y)		((x) > (y) ? (x) : (y))
++#endif
++
++
++/******************************************************************/
++/* Hardware Interrupt functions                                   */
++/******************************************************************/
++
++/* Fast interrupt handler for HC */
++static irqreturn_t crisv10_hcd_top_irq(int irq, void *vcd)
++{
++  struct usb_hcd *hcd = vcd;
++  struct crisv10_irq_reg reg;
++  __u32 irq_mask;
++  unsigned long flags;
++
++  DBFENTER;
++
++  ASSERT(hcd != NULL);
++  reg.hcd = hcd;
++
++  /* Turn of other interrupts while handling these sensitive cases */
++  local_irq_save(flags);
++  
++  /* Read out which interrupts that are flaged */
++  irq_mask = *R_USB_IRQ_MASK_READ;
++  reg.r_usb_irq_mask_read = irq_mask;
++
++  /* Reading R_USB_STATUS clears the ctl_status interrupt. Note that
++     R_USB_STATUS must be read before R_USB_EPID_ATTN since reading the latter
++     clears the ourun and perror fields of R_USB_STATUS. */
++  reg.r_usb_status = *R_USB_STATUS;
++  
++  /* Reading R_USB_EPID_ATTN clears the iso_eof, bulk_eot and epid_attn
++     interrupts. */
++  reg.r_usb_epid_attn = *R_USB_EPID_ATTN;
++  
++  /* Reading R_USB_RH_PORT_STATUS_1 and R_USB_RH_PORT_STATUS_2 clears the
++     port_status interrupt. */
++  reg.r_usb_rh_port_status_1 = *R_USB_RH_PORT_STATUS_1;
++  reg.r_usb_rh_port_status_2 = *R_USB_RH_PORT_STATUS_2;
++  
++  /* Reading R_USB_FM_NUMBER clears the sof interrupt. */
++  /* Note: the lower 11 bits contain the actual frame number, sent with each
++     sof. */
++  reg.r_usb_fm_number = *R_USB_FM_NUMBER;
++
++  /* Interrupts are handled in order of priority. */
++  if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) {
++    crisv10_hcd_port_status_irq(&reg);
++  }
++  if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, epid_attn)) {
++    crisv10_hcd_epid_attn_irq(&reg);
++  }
++  if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, ctl_status)) {
++    crisv10_hcd_ctl_status_irq(&reg);
++  }
++  if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, iso_eof)) {
++    crisv10_hcd_isoc_eof_irq(&reg);
++  }
++  if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, bulk_eot)) {
++    /* Update/restart the bulk start timer since obviously the channel is
++       running. */
++    mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
++    /* Update/restart the bulk eot timer since we just received an bulk eot
++       interrupt. */
++    mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
++
++    /* Check for finished bulk transfers on epids */
++    check_finished_bulk_tx_epids(hcd, 0);
++  }
++  local_irq_restore(flags);
++
++  DBFEXIT;
++  return IRQ_HANDLED;
++}
++
++
++void crisv10_hcd_epid_attn_irq(struct crisv10_irq_reg *reg) {
++  struct usb_hcd *hcd = reg->hcd;
++  struct crisv10_urb_priv *urb_priv;
++  int epid;
++  DBFENTER;
++
++  for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++    if (test_bit(epid, (void *)&reg->r_usb_epid_attn)) {
++      struct urb *urb;
++      __u32 ept_data;
++      int error_code;
++
++      if (epid == DUMMY_EPID || epid == INVALID_EPID) {
++	/* We definitely don't care about these ones. Besides, they are
++	   always disabled, so any possible disabling caused by the
++	   epid attention interrupt is irrelevant. */
++	warn("Got epid_attn for INVALID_EPID or DUMMY_EPID (%d).", epid);
++	continue;
++      }
++
++      if(!epid_inuse(epid)) {
++	irq_err("Epid attention on epid:%d that isn't in use\n", epid);
++	printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++	debug_epid(epid);
++	continue;
++      }
++
++      /* Note that although there are separate R_USB_EPT_DATA and
++	 R_USB_EPT_DATA_ISO registers, they are located at the same address and
++	 are of the same size. In other words, this read should be ok for isoc
++	 also. */
++      ept_data = etrax_epid_get(epid);
++      error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, ept_data);
++
++      /* Get the active URB for this epid. We blatantly assume
++	 that only this URB could have caused the epid attention. */
++      urb = activeUrbList[epid];
++      if (urb == NULL) {
++	irq_err("Attention on epid:%d error:%d with no active URB.\n",
++		epid, error_code);
++	printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++	debug_epid(epid);
++	continue;
++      }
++
++      urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++      ASSERT(urb_priv);
++
++      /* Using IO_STATE_VALUE on R_USB_EPT_DATA should be ok for isoc also. */
++      if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
++
++	/* Isoc traffic doesn't have error_count_in/error_count_out. */
++	if ((usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) &&
++	    (IO_EXTRACT(R_USB_EPT_DATA, error_count_in, ept_data) == 3 ||
++	     IO_EXTRACT(R_USB_EPT_DATA, error_count_out, ept_data) == 3)) {
++	  /* Check if URB allready is marked for late-finish, we can get
++	     several 3rd error for Intr traffic when a device is unplugged */
++	  if(urb_priv->later_data == NULL) {
++	    /* 3rd error. */
++	    irq_warn("3rd error for epid:%d (%s %s) URB:0x%x[%d]\n", epid,
++		     str_dir(urb->pipe), str_type(urb->pipe),
++		     (unsigned int)urb, urb_priv->urb_num);
++	  
++	    tc_finish_urb_later(hcd, urb, -EPROTO);
++	  }
++
++	} else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
++	  irq_warn("Perror for epid:%d\n", epid);
++	  printk("FM_NUMBER: %d\n", reg->r_usb_fm_number & 0x7ff);
++	  printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++	  __dump_urb(urb);
++	  debug_epid(epid);
++
++	  if (!(ept_data & IO_MASK(R_USB_EPT_DATA, valid))) {
++	    /* invalid ep_id */
++	    panic("Perror because of invalid epid."
++		  " Deconfigured too early?");
++	  } else {
++	    /* past eof1, near eof, zout transfer, setup transfer */
++	    /* Dump the urb and the relevant EP descriptor. */
++	    panic("Something wrong with DMA descriptor contents."
++		  " Too much traffic inserted?");
++	  }
++	} else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
++	  /* buffer ourun */
++	  printk("FM_NUMBER: %d\n", reg->r_usb_fm_number & 0x7ff);
++	  printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++	  __dump_urb(urb);
++	  debug_epid(epid);
++
++	  panic("Buffer overrun/underrun for epid:%d. DMA too busy?", epid);
++	} else {
++	  irq_warn("Attention on epid:%d (%s %s) with no error code\n", epid,
++		   str_dir(urb->pipe), str_type(urb->pipe));
++	  printk("R_USB_STATUS: 0x%x\n", reg->r_usb_status);
++	  __dump_urb(urb);
++	  debug_epid(epid);
++	}
++
++      } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code,
++					      stall)) {
++	/* Not really a protocol error, just says that the endpoint gave
++	   a stall response. Note that error_code cannot be stall for isoc. */
++	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++	  panic("Isoc traffic cannot stall");
++	}
++
++	tc_dbg("Stall for epid:%d (%s %s) URB:0x%x\n", epid,
++	       str_dir(urb->pipe), str_type(urb->pipe), (unsigned int)urb);
++	tc_finish_urb(hcd, urb, -EPIPE);
++
++      } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code,
++					      bus_error)) {
++	/* Two devices responded to a transaction request. Must be resolved
++	   by software. FIXME: Reset ports? */
++	panic("Bus error for epid %d."
++	      " Two devices responded to transaction request\n",
++	      epid);
++
++      } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code,
++					      buffer_error)) {
++	/* DMA overrun or underrun. */
++	irq_warn("Buffer overrun/underrun for epid:%d (%s %s)\n", epid,
++		 str_dir(urb->pipe), str_type(urb->pipe));
++
++	/* It seems that error_code = buffer_error in
++	   R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
++	   are the same error. */
++	tc_finish_urb(hcd, urb, -EPROTO);
++      } else {
++	  irq_warn("Unknown attention on epid:%d (%s %s)\n", epid,
++		   str_dir(urb->pipe), str_type(urb->pipe));
++	  dump_ept_data(epid);
++      }
++    }
++  }
++  DBFEXIT;
++}
++
++void crisv10_hcd_port_status_irq(struct crisv10_irq_reg *reg)
++{
++  __u16 port_reg[USB_ROOT_HUB_PORTS];
++  DBFENTER;
++  port_reg[0] = reg->r_usb_rh_port_status_1;
++  port_reg[1] = reg->r_usb_rh_port_status_2;
++  rh_port_status_change(port_reg);
++  DBFEXIT;
++}
++
++void crisv10_hcd_isoc_eof_irq(struct crisv10_irq_reg *reg)
++{
++  int epid;
++  struct urb *urb;
++  struct crisv10_urb_priv *urb_priv;
++
++  DBFENTER;
++
++  for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
++
++    /* Only check epids that are in use, is valid and has SB list */
++    if (!epid_inuse(epid) || epid == INVALID_EPID ||
++	TxIsocEPList[epid].sub == 0 || epid == DUMMY_EPID) {
++      /* Nothing here to see. */
++      continue;
++    }
++    ASSERT(epid_isoc(epid));
++
++    /* Get the active URB for this epid (if any). */
++    urb = activeUrbList[epid];
++    if (urb == 0) {
++      isoc_warn("Ignoring NULL urb for epid:%d\n", epid);
++      continue;
++    }
++    if(!epid_out_traffic(epid)) {
++      /* Sanity check. */
++      ASSERT(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
++
++      urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++      ASSERT(urb_priv);
++
++      if (urb_priv->urb_state == NOT_STARTED) {
++	/* If ASAP is not set and urb->start_frame is the current frame,
++	   start the transfer. */
++	if (!(urb->transfer_flags & URB_ISO_ASAP) &&
++	    (urb->start_frame == (*R_USB_FM_NUMBER & 0x7ff))) {
++	  /* EP should not be enabled if we're waiting for start_frame */
++	  ASSERT((TxIsocEPList[epid].command &
++		  IO_STATE(USB_EP_command, enable, yes)) == 0);
++
++	  isoc_warn("Enabling isoc IN EP descr for epid %d\n", epid);
++	  TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++
++	  /* This urb is now active. */
++	  urb_priv->urb_state = STARTED;
++	  continue;
++	}
++      }
++    }
++  }
++
++  DBFEXIT;
++}
++
++void crisv10_hcd_ctl_status_irq(struct crisv10_irq_reg *reg)
++{
++  struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(reg->hcd);
++
++  DBFENTER;
++  ASSERT(crisv10_hcd);
++
++  irq_dbg("ctr_status_irq, controller status: %s\n",
++	  hcd_status_to_str(reg->r_usb_status));
++  
++  /* FIXME: What should we do if we get ourun or perror? Dump the EP and SB
++     list for the corresponding epid? */
++  if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
++    panic("USB controller got ourun.");
++  }
++  if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
++    
++    /* Before, etrax_usb_do_intr_recover was called on this epid if it was
++       an interrupt pipe. I don't see how re-enabling all EP descriptors
++       will help if there was a programming error. */
++    panic("USB controller got perror.");
++  }
++
++  /* Keep track of USB Controller, if it's running or not */
++  if(reg->r_usb_status & IO_STATE(R_USB_STATUS, running, yes)) {
++    crisv10_hcd->running = 1;
++  } else {
++    crisv10_hcd->running = 0;
++  }
++  
++  if (reg->r_usb_status & IO_MASK(R_USB_STATUS, device_mode)) {
++    /* We should never operate in device mode. */
++    panic("USB controller in device mode.");
++  }
++
++  /* Set the flag to avoid getting "Unlink after no-IRQ? Controller is probably
++     using the wrong IRQ" from hcd_unlink_urb() in drivers/usb/core/hcd.c */
++  set_bit(HCD_FLAG_SAW_IRQ, &reg->hcd->flags);
++  
++  DBFEXIT;
++}
++
++
++/******************************************************************/
++/* Host Controller interface functions                            */
++/******************************************************************/
++
++static inline void crisv10_ready_wait(void) {
++  volatile int timeout = 10000;
++  /* Check the busy bit of USB controller in Etrax */
++  while((*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)) &&
++	(timeout-- > 0));
++  if(timeout == 0) {
++    warn("Timeout while waiting for USB controller to be idle\n");
++  }
++}
++
++/* reset host controller */
++static int crisv10_hcd_reset(struct usb_hcd *hcd)
++{
++  DBFENTER;
++  hcd_dbg(hcd, "reset\n");
++
++
++  /* Reset the USB interface. */
++  /*
++  *R_USB_COMMAND =
++    IO_STATE(R_USB_COMMAND, port_sel, nop) |
++    IO_STATE(R_USB_COMMAND, port_cmd, reset) |
++    IO_STATE(R_USB_COMMAND, ctrl_cmd, reset);
++  nop();
++  */
++  DBFEXIT;
++  return 0;
++}
++
++/* start host controller */
++static int crisv10_hcd_start(struct usb_hcd *hcd)
++{
++  DBFENTER;
++  hcd_dbg(hcd, "start\n");
++
++  crisv10_ready_wait();
++
++  /* Start processing of USB traffic. */
++  *R_USB_COMMAND =
++    IO_STATE(R_USB_COMMAND, port_sel, nop) |
++    IO_STATE(R_USB_COMMAND, port_cmd, reset) |
++    IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
++
++  nop();
++
++  hcd->state = HC_STATE_RUNNING;
++
++  DBFEXIT;
++  return 0;
++}
++
++/* stop host controller */
++static void crisv10_hcd_stop(struct usb_hcd *hcd)
++{
++  DBFENTER;
++  hcd_dbg(hcd, "stop\n");
++  crisv10_hcd_reset(hcd);
++  DBFEXIT;
++}
++
++/* return the current frame number */
++static int crisv10_hcd_get_frame(struct usb_hcd *hcd)
++{
++  DBFENTER;
++  DBFEXIT;
++  return (*R_USB_FM_NUMBER & 0x7ff);
++}
++
++#ifdef	CONFIG_USB_OTG
++
++static int crisv10_hcd_start_port_reset(struct usb_hcd *hcd, unsigned port)
++{
++  return 0; /* no-op for now */
++}
++
++#endif /* CONFIG_USB_OTG */
++
++
++/******************************************************************/
++/* Root Hub functions                                             */
++/******************************************************************/
++
++/* root hub status */
++static const struct usb_hub_status rh_hub_status = 
++  {
++    .wHubStatus =		0,
++    .wHubChange =		0,
++  };
++
++/* root hub descriptor */
++static const u8 rh_hub_descr[] =
++  {
++    0x09,			/* bDescLength	       */
++    0x29,			/* bDescriptorType     */
++    USB_ROOT_HUB_PORTS,         /* bNbrPorts	       */
++    0x00,			/* wHubCharacteristics */
++    0x00,		 
++    0x01,			/* bPwrOn2pwrGood      */
++    0x00,			/* bHubContrCurrent    */
++    0x00,			/* DeviceRemovable     */
++    0xff			/* PortPwrCtrlMask     */
++  };
++
++/* Actual holder of root hub status*/
++struct crisv10_rh rh;
++
++/* Initialize root hub data structures (called from dvdrv_hcd_probe()) */
++int rh_init(void) {
++  int i;
++  /* Reset port status flags */
++  for (i = 0; i < USB_ROOT_HUB_PORTS; i++) {
++    rh.wPortChange[i] = 0;
++    rh.wPortStatusPrev[i] = 0;
++  }
++  return 0;
++}
++
++#define RH_FEAT_MASK ((1<<USB_PORT_FEAT_CONNECTION)|\
++		      (1<<USB_PORT_FEAT_ENABLE)|\
++		      (1<<USB_PORT_FEAT_SUSPEND)|\
++		      (1<<USB_PORT_FEAT_RESET))
++
++/* Handle port status change interrupt (called from bottom part interrupt) */
++void rh_port_status_change(__u16 port_reg[]) {
++  int i;
++  __u16 wChange;
++
++  for(i = 0; i < USB_ROOT_HUB_PORTS; i++) {
++    /* Xor out changes since last read, masked for important flags */
++    wChange = (port_reg[i] & RH_FEAT_MASK) ^ rh.wPortStatusPrev[i];
++    /* Or changes together with (if any) saved changes */
++    rh.wPortChange[i] |= wChange;
++    /* Save new status */
++    rh.wPortStatusPrev[i] = port_reg[i];
++
++    if(wChange) {
++      rh_dbg("Interrupt port_status change port%d: %s  Current-status:%s\n", i+1,
++	     port_status_to_str(wChange),
++	     port_status_to_str(port_reg[i]));
++    }
++  }
++}
++
++/* Construct port status change bitmap for the root hub */
++static int rh_status_data_request(struct usb_hcd *hcd, char *buf)
++{
++  struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++  unsigned int i;
++
++//  DBFENTER;
++  
++  /*
++   * corresponds to hub status change EP (USB 2.0 spec section 11.13.4)
++   * return bitmap indicating ports with status change
++   */
++  *buf = 0;
++  spin_lock(&crisv10_hcd->lock);
++  for (i = 1; i <= crisv10_hcd->num_ports; i++) {
++    if (rh.wPortChange[map_port(i)]) {
++      *buf |= (1 << i);
++      rh_dbg("rh_status_data_request, change on port %d: %s  Current Status: %s\n", i,
++	     port_status_to_str(rh.wPortChange[map_port(i)]),
++	     port_status_to_str(rh.wPortStatusPrev[map_port(i)]));
++    }
++  }
++  spin_unlock(&crisv10_hcd->lock);
++
++// DBFEXIT;
++
++  return *buf == 0 ? 0 : 1;
++}
++
++/* Handle a control request for the root hub (called from hcd_driver) */
++static int rh_control_request(struct usb_hcd *hcd, 
++			      u16 typeReq, 
++			      u16 wValue, 
++			      u16 wIndex,
++			      char *buf, 
++			      u16 wLength) {
++
++  struct crisv10_hcd *crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++  int retval = 0;
++  int len;
++  DBFENTER;
++
++  switch (typeReq) {
++  case GetHubDescriptor:
++    rh_dbg("GetHubDescriptor\n");
++    len = min_t(unsigned int, sizeof rh_hub_descr, wLength);
++    memcpy(buf, rh_hub_descr, len);
++    buf[2] = crisv10_hcd->num_ports;
++    break;
++  case GetHubStatus:
++    rh_dbg("GetHubStatus\n");
++    len = min_t(unsigned int, sizeof rh_hub_status, wLength);
++    memcpy(buf, &rh_hub_status, len);
++    break;
++  case GetPortStatus:
++    if (!wIndex || wIndex > crisv10_hcd->num_ports)
++      goto error;
++    rh_dbg("GetportStatus, port:%d change:%s  status:%s\n", wIndex,
++	   port_status_to_str(rh.wPortChange[map_port(wIndex)]),
++	   port_status_to_str(rh.wPortStatusPrev[map_port(wIndex)]));
++    *(u16 *) buf = cpu_to_le16(rh.wPortStatusPrev[map_port(wIndex)]);
++    *(u16 *) (buf + 2) = cpu_to_le16(rh.wPortChange[map_port(wIndex)]);
++    break;
++  case SetHubFeature:
++    rh_dbg("SetHubFeature\n");
++  case ClearHubFeature:
++    rh_dbg("ClearHubFeature\n");
++    switch (wValue) {
++    case C_HUB_OVER_CURRENT:
++    case C_HUB_LOCAL_POWER:
++      rh_warn("Not implemented hub request:%d \n", typeReq);
++      /* not implemented */
++      break;
++    default:
++      goto error;
++    }
++    break;
++  case SetPortFeature:
++    if (!wIndex || wIndex > crisv10_hcd->num_ports)
++      goto error;
++    if(rh_set_port_feature(map_port(wIndex), wValue))
++      goto error;
++    break;
++  case ClearPortFeature:
++    if (!wIndex || wIndex > crisv10_hcd->num_ports)
++      goto error;
++    if(rh_clear_port_feature(map_port(wIndex), wValue))
++      goto error;
++    break;
++  default:
++    rh_warn("Unknown hub request: %d\n", typeReq);
++  error:
++    retval = -EPIPE;
++  }
++  DBFEXIT;
++  return retval;
++}
++
++int rh_set_port_feature(__u8 bPort, __u16 wFeature) {
++  __u8 bUsbCommand = 0;
++  switch(wFeature) {
++  case USB_PORT_FEAT_RESET:
++    rh_dbg("SetPortFeature: reset\n");
++    bUsbCommand |= IO_STATE(R_USB_COMMAND, port_cmd, reset);
++    goto set;
++    break;
++  case USB_PORT_FEAT_SUSPEND:
++    rh_dbg("SetPortFeature: suspend\n");
++    bUsbCommand |= IO_STATE(R_USB_COMMAND, port_cmd, suspend);
++    goto set;
++    break;
++  case USB_PORT_FEAT_POWER:
++    rh_dbg("SetPortFeature: power\n");
++    break;
++  case USB_PORT_FEAT_C_CONNECTION:
++    rh_dbg("SetPortFeature: c_connection\n");
++    break;
++  case USB_PORT_FEAT_C_RESET:
++    rh_dbg("SetPortFeature: c_reset\n");
++    break;
++  case USB_PORT_FEAT_C_OVER_CURRENT:
++    rh_dbg("SetPortFeature: c_over_current\n");
++    break;
++
++  set:
++    /* Select which port via the port_sel field */
++    bUsbCommand |= IO_FIELD(R_USB_COMMAND, port_sel, bPort+1);
++
++    /* Make sure the controller isn't busy. */
++    crisv10_ready_wait();
++    /* Send out the actual command to the USB controller */
++    *R_USB_COMMAND = bUsbCommand;
++
++    /* If port reset then also bring USB controller into running state */
++    if(wFeature == USB_PORT_FEAT_RESET) {
++      /* Wait a while for controller to first become started after port reset */
++      udelay(12000); /* 12ms blocking wait */
++      
++      /* Make sure the controller isn't busy. */
++      crisv10_ready_wait();
++
++      /* If all enabled ports were disabled the host controller goes down into
++	 started mode, so we need to bring it back into the running state.
++	 (This is safe even if it's already in the running state.) */
++      *R_USB_COMMAND =
++	IO_STATE(R_USB_COMMAND, port_sel, nop) |
++	IO_STATE(R_USB_COMMAND, port_cmd, reset) |
++	IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
++    }
++
++    break;
++  default:
++    rh_dbg("SetPortFeature: unknown feature\n");
++    return -1;
++  }
++  return 0;
++}
++
++int rh_clear_port_feature(__u8 bPort, __u16 wFeature) {
++  switch(wFeature) {
++  case USB_PORT_FEAT_ENABLE:
++    rh_dbg("ClearPortFeature: enable\n");
++    rh_disable_port(bPort);
++    break;
++  case USB_PORT_FEAT_SUSPEND:
++    rh_dbg("ClearPortFeature: suspend\n");
++    break;
++  case USB_PORT_FEAT_POWER:
++    rh_dbg("ClearPortFeature: power\n");
++    break;
++
++  case USB_PORT_FEAT_C_ENABLE:
++    rh_dbg("ClearPortFeature: c_enable\n");
++    goto clear;
++  case USB_PORT_FEAT_C_SUSPEND:
++    rh_dbg("ClearPortFeature: c_suspend\n");
++    goto clear;
++  case USB_PORT_FEAT_C_CONNECTION:
++    rh_dbg("ClearPortFeature: c_connection\n");
++    goto clear;
++  case USB_PORT_FEAT_C_OVER_CURRENT:
++    rh_dbg("ClearPortFeature: c_over_current\n");
++    goto clear;
++  case USB_PORT_FEAT_C_RESET:
++    rh_dbg("ClearPortFeature: c_reset\n");
++    goto clear;
++  clear:
++    rh.wPortChange[bPort] &= ~(1 << (wFeature - 16));
++    break;
++  default:
++    rh_dbg("ClearPortFeature: unknown feature\n");
++    return -1;
++  }
++  return 0;
++}
++
++
++#ifdef	CONFIG_PM
++/* Handle a suspend request for the root hub (called from hcd_driver) */
++static int rh_suspend_request(struct usb_hcd *hcd)
++{
++  return 0; /* no-op for now */
++}
++
++/* Handle a resume request for the root hub (called from hcd_driver) */
++static int rh_resume_request(struct usb_hcd *hcd)
++{
++  return 0; /* no-op for now */
++}
++#endif /* CONFIG_PM */
++
++
++
++/* Wrapper function for workaround port disable registers in USB controller  */
++static void rh_disable_port(unsigned int port) {
++  volatile int timeout = 10000;
++  volatile char* usb_portx_disable;
++  switch(port) {
++  case 0:
++    usb_portx_disable = R_USB_PORT1_DISABLE;
++    break;
++  case 1:
++    usb_portx_disable = R_USB_PORT2_DISABLE;
++    break;
++  default:
++    /* Invalid port index */
++    return;
++  }
++  /* Set disable flag in special register  */
++  *usb_portx_disable = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
++  /* Wait until not enabled anymore */
++  while((rh.wPortStatusPrev[port] &
++	IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)) &&
++	(timeout-- > 0));
++  if(timeout == 0) {
++    warn("Timeout while waiting for port %d to become disabled\n", port);
++  }
++  /* clear disable flag in special register  */
++  *usb_portx_disable = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
++  rh_info("Physical port %d disabled\n", port+1);
++}
++
++
++/******************************************************************/
++/* Transfer Controller (TC) functions                             */
++/******************************************************************/
++
++/* FIXME: Should RX_BUF_SIZE be a config option, or maybe we should adjust it
++   dynamically?
++   To adjust it dynamically we would have to get an interrupt when we reach
++   the end of the rx descriptor list, or when we get close to the end, and
++   then allocate more descriptors. */
++#define NBR_OF_RX_DESC     512
++#define RX_DESC_BUF_SIZE   1024
++#define RX_BUF_SIZE        (NBR_OF_RX_DESC * RX_DESC_BUF_SIZE)
++
++
++/* Local variables for Transfer Controller */
++/* --------------------------------------- */
++
++/* This is a circular (double-linked) list of the active urbs for each epid.
++   The head is never removed, and new urbs are linked onto the list as
++   urb_entry_t elements. Don't reference urb_list directly; use the wrapper
++   functions instead (which includes spin_locks) */
++static struct list_head urb_list[NBR_OF_EPIDS];
++
++/* Read about the need and usage of this lock in submit_ctrl_urb. */
++/* Lock for URB lists for each EPID */
++static spinlock_t urb_list_lock;
++
++/* Lock for EPID array register (R_USB_EPT_x) in Etrax */
++static spinlock_t etrax_epid_lock;
++
++/* Lock for dma8 sub0 handling */
++static spinlock_t etrax_dma8_sub0_lock;
++
++/* DMA IN cache bug. Align the DMA IN buffers to 32 bytes, i.e. a cache line.
++   Since RX_DESC_BUF_SIZE is 1024 is a multiple of 32, all rx buffers will be
++   cache aligned. */
++static volatile unsigned char RxBuf[RX_BUF_SIZE] __attribute__ ((aligned (32)));
++static volatile struct USB_IN_Desc RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));
++
++/* Pointers into RxDescList. */
++static volatile struct USB_IN_Desc *myNextRxDesc;
++static volatile struct USB_IN_Desc *myLastRxDesc;
++
++/* A zout transfer makes a memory access at the address of its buf pointer,
++   which means that setting this buf pointer to 0 will cause an access to the
++   flash. In addition to this, setting sw_len to 0 results in a 16/32 bytes
++   (depending on DMA burst size) transfer.
++   Instead, we set it to 1, and point it to this buffer. */
++static int zout_buffer[4] __attribute__ ((aligned (4)));
++
++/* Cache for allocating new EP and SB descriptors. */
++//static kmem_cache_t *usb_desc_cache;
++static struct kmem_cache *usb_desc_cache;
++
++/* Cache for the data allocated in the isoc descr top half. */
++//static kmem_cache_t *isoc_compl_cache;
++static struct kmem_cache *isoc_compl_cache;
++
++/* Cache for the data allocated when delayed finishing of URBs */
++//static kmem_cache_t *later_data_cache;
++static struct kmem_cache *later_data_cache;
++
++/* Counter to keep track of how many Isoc EP we have sat up. Used to enable
++   and disable iso_eof interrupt. We only need these interrupts when we have
++   Isoc data endpoints (consumes CPU cycles).
++   FIXME: This could be more fine granular, so this interrupt is only enabled
++   when we have a In Isoc URB not URB_ISO_ASAP flaged queued. */
++static int isoc_epid_counter;
++
++/* Protecting wrapper functions for R_USB_EPT_x */
++/* -------------------------------------------- */
++static inline void etrax_epid_set(__u8 index, __u32 data) {
++  unsigned long flags;
++  spin_lock_irqsave(&etrax_epid_lock, flags);
++  *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++  nop();
++  *R_USB_EPT_DATA = data;
++  spin_unlock_irqrestore(&etrax_epid_lock, flags);
++}
++
++static inline void etrax_epid_clear_error(__u8 index) {
++  unsigned long flags;
++  spin_lock_irqsave(&etrax_epid_lock, flags);
++  *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++  nop();
++  *R_USB_EPT_DATA &=
++    ~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
++      IO_MASK(R_USB_EPT_DATA, error_count_out) |
++      IO_MASK(R_USB_EPT_DATA, error_code));
++  spin_unlock_irqrestore(&etrax_epid_lock, flags);
++}
++
++static inline void etrax_epid_set_toggle(__u8 index, __u8 dirout,
++                                             __u8 toggle) {
++  unsigned long flags;
++  spin_lock_irqsave(&etrax_epid_lock, flags);
++  *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++  nop();
++  if(dirout) {
++    *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out);
++    *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle);
++  } else {
++    *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in);
++    *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle);
++  }
++  spin_unlock_irqrestore(&etrax_epid_lock, flags);
++}
++
++static inline __u8 etrax_epid_get_toggle(__u8 index, __u8 dirout) {
++  unsigned long flags;
++  __u8 toggle;
++  spin_lock_irqsave(&etrax_epid_lock, flags);
++  *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++  nop();
++  if (dirout) {
++    toggle = IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA);
++  } else {
++    toggle = IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA);
++  }
++  spin_unlock_irqrestore(&etrax_epid_lock, flags);
++  return toggle;
++}
++
++
++static inline __u32 etrax_epid_get(__u8 index) {
++  unsigned long flags;
++  __u32 data;
++  spin_lock_irqsave(&etrax_epid_lock, flags);
++  *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, index);
++  nop();
++  data = *R_USB_EPT_DATA;
++  spin_unlock_irqrestore(&etrax_epid_lock, flags);
++  return data;
++}
++
++
++
++
++/* Main functions for Transfer Controller */
++/* -------------------------------------- */
++
++/* Init structs, memories and lists used by Transfer Controller */
++int tc_init(struct usb_hcd *hcd) {
++  int i;
++  /* Clear software state info for all epids */
++  memset(epid_state, 0, sizeof(struct etrax_epid) * NBR_OF_EPIDS);
++
++  /* Set Invalid and Dummy as being in use and disabled */
++  epid_state[INVALID_EPID].inuse = 1;
++  epid_state[DUMMY_EPID].inuse = 1;
++  epid_state[INVALID_EPID].disabled = 1;
++  epid_state[DUMMY_EPID].disabled = 1;
++
++  /* Clear counter for how many Isoc epids we have sat up */
++  isoc_epid_counter = 0;
++
++  /* Initialize the urb list by initiating a head for each list.
++     Also reset list hodling active URB for each epid */
++  for (i = 0; i < NBR_OF_EPIDS; i++) {
++    INIT_LIST_HEAD(&urb_list[i]);
++    activeUrbList[i] = NULL;
++  }
++
++  /* Init lock for URB lists */
++  spin_lock_init(&urb_list_lock);
++  /* Init lock for Etrax R_USB_EPT register */
++  spin_lock_init(&etrax_epid_lock);
++  /* Init lock for Etrax dma8 sub0 handling */
++  spin_lock_init(&etrax_dma8_sub0_lock);
++
++  /* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */
++
++  /* Note that we specify sizeof(struct USB_EP_Desc) as the size, but also
++     allocate SB descriptors from this cache. This is ok since
++     sizeof(struct USB_EP_Desc) == sizeof(struct USB_SB_Desc). */
++//  usb_desc_cache = kmem_cache_create("usb_desc_cache",
++//				     sizeof(struct USB_EP_Desc), 0,
++//				     SLAB_HWCACHE_ALIGN, 0, 0);
++  usb_desc_cache = kmem_cache_create(
++				  "usb_desc_cache",
++				  sizeof(struct USB_EP_Desc),
++				  0,
++				  SLAB_HWCACHE_ALIGN,
++				  NULL);
++  if(usb_desc_cache == NULL) {
++    return -ENOMEM;
++  }
++
++  /* Create slab cache for speedy allocation of memory for isoc bottom-half
++     interrupt handling */
++//  isoc_compl_cache =
++//    kmem_cache_create("isoc_compl_cache",
++//		      sizeof(struct crisv10_isoc_complete_data),
++//		      0, SLAB_HWCACHE_ALIGN, 0, 0);
++  isoc_compl_cache = kmem_cache_create(
++				  "isoc_compl_cache",
++				  sizeof(struct crisv10_isoc_complete_data),
++				  0,
++				  SLAB_HWCACHE_ALIGN,
++				  NULL
++				  );
++
++  if(isoc_compl_cache == NULL) {
++    return -ENOMEM;
++  }
++
++  /* Create slab cache for speedy allocation of memory for later URB finish
++     struct */
++//  later_data_cache =
++//    kmem_cache_create("later_data_cache",
++//		      sizeof(struct urb_later_data),
++//		      0, SLAB_HWCACHE_ALIGN, 0, 0);
++
++  later_data_cache = kmem_cache_create(
++				  "later_data_cache",
++				  sizeof(struct urb_later_data),
++				  0,
++				  SLAB_HWCACHE_ALIGN,
++				  NULL
++				  );
++  
++  if(later_data_cache == NULL) {
++    return -ENOMEM;
++  }
++
++
++  /* Initiate the bulk start timer. */
++  init_timer(&bulk_start_timer);
++  bulk_start_timer.expires = jiffies + BULK_START_TIMER_INTERVAL;
++  bulk_start_timer.function = tc_bulk_start_timer_func;
++  add_timer(&bulk_start_timer);
++
++
++  /* Initiate the bulk eot timer. */
++  init_timer(&bulk_eot_timer);
++  bulk_eot_timer.expires = jiffies + BULK_EOT_TIMER_INTERVAL;
++  bulk_eot_timer.function = tc_bulk_eot_timer_func;
++  bulk_eot_timer.data = (unsigned long)hcd;
++  add_timer(&bulk_eot_timer);
++
++  return 0;
++}
++
++/* Uninitialize all resources used by Transfer Controller */
++void tc_destroy(void) {
++
++  /* Destroy all slab cache */
++  kmem_cache_destroy(usb_desc_cache);
++  kmem_cache_destroy(isoc_compl_cache);
++  kmem_cache_destroy(later_data_cache);
++
++  /* Remove timers */
++  del_timer(&bulk_start_timer);
++  del_timer(&bulk_eot_timer);
++}
++
++static void restart_dma8_sub0(void) {
++  unsigned long flags;
++  spin_lock_irqsave(&etrax_dma8_sub0_lock, flags);
++  /* Verify that the dma is not running */
++  if ((*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd)) == 0) {
++    struct USB_EP_Desc *ep = (struct USB_EP_Desc *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
++    while (DUMMY_EPID == IO_EXTRACT(USB_EP_command, epid, ep->command)) {
++      ep = (struct USB_EP_Desc *)phys_to_virt(ep->next);
++    }
++    /* Advance the DMA to the next EP descriptor that is not a DUMMY_EPID.
++	 * ep->next is already a physical address. virt_to_phys is needed, see
++	 * http://mhonarc.axis.se/dev-etrax/msg08630.html
++	 */
++    //*R_DMA_CH8_SUB0_EP = ep->next;
++	*R_DMA_CH8_SUB0_EP = virt_to_phys(ep);
++    /* Restart the DMA */
++    *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
++  }
++  spin_unlock_irqrestore(&etrax_dma8_sub0_lock, flags);
++}
++
++/* queue an URB with the transfer controller (called from hcd_driver) */
++//static int tc_urb_enqueue(struct usb_hcd *hcd, 
++//			  struct usb_host_endpoint *ep,
++//			  struct urb *urb, 
++//			  gfp_t mem_flags) {
++static int tc_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
++{
++  int epid;
++  int retval;
++//  int bustime = 0;
++  int maxpacket;
++  unsigned long flags;
++  struct crisv10_urb_priv *urb_priv;
++  struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++  DBFENTER;
++
++  if(!(crisv10_hcd->running)) {
++    /* The USB Controller is not running, probably because no device is 
++       attached. No idea to enqueue URBs then */
++    tc_warn("Rejected enqueueing of URB:0x%x because no dev attached\n",
++	    (unsigned int)urb);
++    return -ENOENT;
++  }
++
++  maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
++  
++  /* hinko ignore usb_pipeisoc */
++#if 0
++  /* Special case check for In Isoc transfers. Specification states that each
++     In Isoc transfer consists of one packet and therefore it should fit into
++     the transfer-buffer of an URB.
++     We do the check here to be sure (an invalid scenario can be produced with
++     parameters to the usbtest suite) */
++  if(usb_pipeisoc(urb->pipe) && usb_pipein(urb->pipe) &&
++     (urb->transfer_buffer_length < maxpacket)) {
++    tc_err("Submit In Isoc URB with buffer length:%d to pipe with maxpacketlen: %d\n", urb->transfer_buffer_length, maxpacket);
++    return -EMSGSIZE;
++  }
++
++  /* Check if there is enough bandwidth for periodic transfer  */
++  if(usb_pipeint(urb->pipe) || usb_pipeisoc(urb->pipe)) {
++    /* only check (and later claim) if not already claimed */
++    if (urb->bandwidth == 0) {
++      bustime = usb_check_bandwidth(urb->dev, urb);
++      if (bustime < 0) {
++	tc_err("Not enough periodic bandwidth\n");
++	return -ENOSPC;
++      }
++    }
++  }
++#endif
++  
++  /* Check if there is a epid for URBs destination, if not this function
++     set up one. */
++  //epid = tc_setup_epid(ep, urb, mem_flags);
++  epid = tc_setup_epid(urb, mem_flags);
++  if (epid < 0) {
++    tc_err("Failed setup epid:%d for URB:0x%x\n", epid, (unsigned int)urb);
++    DBFEXIT;
++    return -ENOMEM;
++  }
++
++  if(urb == activeUrbList[epid]) {
++    tc_err("Resubmition of allready active URB:0x%x\n", (unsigned int)urb);
++    return -ENXIO;
++  }
++
++  if(urb_list_entry(urb, epid)) {
++    tc_err("Resubmition of allready queued URB:0x%x\n", (unsigned int)urb);
++    return -ENXIO;
++  }
++
++  /* If we actively have flaged endpoint as disabled then refuse submition */
++  if(epid_state[epid].disabled) {
++    return -ENOENT;
++  }
++
++  /* Allocate and init HC-private data for URB */
++  if(urb_priv_create(hcd, urb, epid, mem_flags) != 0) {
++    DBFEXIT;
++    return -ENOMEM;
++  }
++  urb_priv = urb->hcpriv;
++
++  tc_dbg("Enqueue URB:0x%x[%d] epid:%d (%s) bufflen:%d\n",
++	 (unsigned int)urb, urb_priv->urb_num, epid,
++	 pipe_to_str(urb->pipe), urb->transfer_buffer_length);
++
++  /* Create and link SBs required for this URB */
++  retval = create_sb_for_urb(urb, mem_flags);
++  if(retval != 0) {
++    tc_err("Failed to create SBs for URB:0x%x[%d]\n", (unsigned int)urb,
++	   urb_priv->urb_num);
++    urb_priv_free(hcd, urb);
++    DBFEXIT;
++    return retval;
++  }
++
++  /* Init intr EP pool if this URB is a INTR transfer. This pool is later
++     used when inserting EPs in the TxIntrEPList. We do the alloc here
++     so we can't run out of memory later */
++  if(usb_pipeint(urb->pipe)) {
++    retval = init_intr_urb(urb, mem_flags);
++    if(retval != 0) {
++      tc_warn("Failed to init Intr URB\n");
++      urb_priv_free(hcd, urb);
++      DBFEXIT;
++      return retval;
++    }
++  }
++
++  /* Disable other access when inserting USB */
++
++  /* BUG on sleeping inside int disabled if using local_irq_save/local_irq_restore
++   * her - because urb_list_add() and tc_dma_process_queue() save irqs again !??!
++   */
++//  local_irq_save(flags);
++
++  /* hinko ignore usb_pipeisoc */
++#if 0
++  /* Claim bandwidth, if needed */
++  if(bustime) {
++    usb_claim_bandwidth(urb->dev, urb, bustime, 0);
++  }
++  
++  /* Add URB to EP queue */
++  urb_list_add(urb, epid, mem_flags);
++
++  if(usb_pipeisoc(urb->pipe)) {
++    /* Special processing of Isoc URBs. */
++    tc_dma_process_isoc_urb(urb);
++  } else {
++    /* Process EP queue for rest of the URB types (Bulk, Ctrl, Intr) */
++    tc_dma_process_queue(epid);
++  }
++#endif
++  /* Add URB to EP queue */
++  urb_list_add(urb, epid, mem_flags);
++
++  /*hinko link/unlink urb -> ep */
++  spin_lock_irqsave(&crisv10_hcd->lock, flags);
++  //spin_lock(&crisv10_hcd->lock);
++  retval = usb_hcd_link_urb_to_ep(hcd, urb);
++  if (retval) {
++    spin_unlock_irqrestore(&crisv10_hcd->lock, flags);
++    tc_warn("Failed to link urb to ep\n");
++    urb_priv_free(hcd, urb);
++    DBFEXIT;
++    return retval;
++  }
++  spin_unlock_irqrestore(&crisv10_hcd->lock, flags);
++  //spin_unlock(&crisv10_hcd->lock);
++  
++  /* Process EP queue for rest of the URB types (Bulk, Ctrl, Intr) */
++  tc_dma_process_queue(epid);
++
++//  local_irq_restore(flags);
++
++  DBFEXIT;
++  return 0;
++}
++
++/* remove an URB from the transfer controller queues (called from hcd_driver)*/
++//static int tc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
++static int tc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
++{
++  struct crisv10_urb_priv *urb_priv;
++  unsigned long flags;
++  int epid;
++
++  DBFENTER;
++  /* Disable interrupts here since a descriptor interrupt for the isoc epid
++     will modify the sb list.  This could possibly be done more granular, but
++     urb_dequeue should not be used frequently anyway.
++  */
++  local_irq_save(flags);
++
++  urb_priv = urb->hcpriv;
++
++  if (!urb_priv) {
++    /* This happens if a device driver calls unlink on an urb that
++       was never submitted (lazy driver) or if the urb was completed
++       while dequeue was being called. */
++    tc_warn("Dequeing of not enqueued URB:0x%x\n", (unsigned int)urb);
++    local_irq_restore(flags);
++    return 0;
++  }
++  epid = urb_priv->epid;
++
++  tc_warn("Dequeing %s URB:0x%x[%d] (%s %s epid:%d) status:%d %s\n",
++	  (urb == activeUrbList[epid]) ? "active" : "queued",
++	  (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++	  str_type(urb->pipe), epid, urb->status,
++	  (urb_priv->later_data) ? "later-sched" : "");
++
++  /* For Bulk, Ctrl and Intr are only one URB active at a time. So any URB
++     that isn't active can be dequeued by just removing it from the queue */
++  if(usb_pipebulk(urb->pipe) || usb_pipecontrol(urb->pipe) ||
++     usb_pipeint(urb->pipe)) {
++
++    /* Check if URB haven't gone further than the queue */
++    if(urb != activeUrbList[epid]) {
++      ASSERT(urb_priv->later_data == NULL);
++      tc_warn("Dequeing URB:0x%x[%d] (%s %s epid:%d) from queue"
++	      " (not active)\n", (unsigned int)urb, urb_priv->urb_num,
++	      str_dir(urb->pipe), str_type(urb->pipe), epid);
++      
++      /* Finish the URB with error status from USB core */
++      tc_finish_urb(hcd, urb, urb->status);
++      local_irq_restore(flags);
++      return 0;
++    }
++  }
++
++  /* Set URB status to Unlink for handling when interrupt comes. */
++  urb_priv->urb_state = UNLINK;
++
++  /* Differentiate dequeing of Bulk and Ctrl from Isoc and Intr */
++  switch(usb_pipetype(urb->pipe)) {
++  case PIPE_BULK:
++    /* Check if EP still is enabled */
++    if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++      /* The EP was enabled, disable it. */
++      TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++    }
++    /* Kicking dummy list out of the party. */
++    TxBulkEPList[epid].next = virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
++    break;
++  case PIPE_CONTROL:
++    /* Check if EP still is enabled */
++    if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++      /* The EP was enabled, disable it. */
++      TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++    }
++    break;
++  case PIPE_ISOCHRONOUS:
++    /* Disabling, busy-wait and unlinking of Isoc SBs will be done in
++       finish_isoc_urb(). Because there might the case when URB is dequeued
++       but there are other valid URBs waiting */
++
++    /* Check if In Isoc EP still is enabled */
++    if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++      /* The EP was enabled, disable it. */
++      TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++    }
++    break;
++  case PIPE_INTERRUPT:
++    /* Special care is taken for interrupt URBs. EPs are unlinked in
++       tc_finish_urb */
++    break;
++  default:
++    break;
++  }
++
++  /* Asynchronous unlink, finish the URB later from scheduled or other
++     event (data finished, error) */
++  tc_finish_urb_later(hcd, urb, urb->status);
++
++  local_irq_restore(flags);
++  DBFEXIT;
++  return 0;
++}
++
++
++static void tc_sync_finish_epid(struct usb_hcd *hcd, int epid) {
++  volatile int timeout = 10000;
++  struct urb* urb;
++  struct crisv10_urb_priv* urb_priv;
++  unsigned long flags;
++  
++  volatile struct USB_EP_Desc *first_ep;  /* First EP in the list. */
++  volatile struct USB_EP_Desc *curr_ep;   /* Current EP, the iterator. */
++  volatile struct USB_EP_Desc *next_ep;   /* The EP after current. */
++
++  int type = epid_state[epid].type;
++
++  /* Setting this flag will cause enqueue() to return -ENOENT for new
++     submitions on this endpoint and finish_urb() wont process queue further */
++  epid_state[epid].disabled = 1;
++
++  switch(type) {
++  case PIPE_BULK:
++    /* Check if EP still is enabled */
++    if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++      /* The EP was enabled, disable it. */
++      TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++      tc_warn("sync_finish: Disabling EP for epid:%d\n", epid);
++
++      /* Do busy-wait until DMA not using this EP descriptor anymore */
++      while((*R_DMA_CH8_SUB0_EP ==
++	     virt_to_phys(&TxBulkEPList[epid])) &&
++	    (timeout-- > 0));
++      if(timeout == 0) {
++	warn("Timeout while waiting for DMA-TX-Bulk to leave EP for"
++	     " epid:%d\n", epid);
++      }
++    }
++    break;
++
++  case PIPE_CONTROL:
++    /* Check if EP still is enabled */
++    if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++      /* The EP was enabled, disable it. */
++      TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++      tc_warn("sync_finish: Disabling EP for epid:%d\n", epid);
++
++      /* Do busy-wait until DMA not using this EP descriptor anymore */
++      while((*R_DMA_CH8_SUB1_EP ==
++	     virt_to_phys(&TxCtrlEPList[epid])) &&
++	    (timeout-- > 0));
++      if(timeout == 0) {
++	warn("Timeout while waiting for DMA-TX-Ctrl to leave EP for"
++	     " epid:%d\n", epid);
++      }
++    }
++    break;
++
++  case PIPE_INTERRUPT:
++    local_irq_save(flags);
++    /* Disable all Intr EPs belonging to epid */
++    first_ep = &TxIntrEPList[0];
++    curr_ep = first_ep;
++    do {
++      next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++      if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
++	/* Disable EP */
++	next_ep->command &= ~IO_MASK(USB_EP_command, enable);
++      }
++      curr_ep = phys_to_virt(curr_ep->next);
++    } while (curr_ep != first_ep);
++
++    local_irq_restore(flags);
++    break;
++
++  case PIPE_ISOCHRONOUS:
++    /* Check if EP still is enabled */
++    if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++      tc_warn("sync_finish: Disabling Isoc EP for epid:%d\n", epid);
++      /* The EP was enabled, disable it. */
++      TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++      
++      while((*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid])) &&
++	    (timeout-- > 0));
++      if(timeout == 0) {
++	warn("Timeout while waiting for DMA-TX-Isoc to leave EP for"
++	     " epid:%d\n", epid);
++      }
++    }
++    break;
++  }
++
++  local_irq_save(flags);
++
++  /* Finish if there is active URB for this endpoint */
++  if(activeUrbList[epid] != NULL) {
++    urb = activeUrbList[epid];
++    urb_priv = urb->hcpriv;
++    ASSERT(urb_priv);
++    tc_warn("Sync finish %s URB:0x%x[%d] (%s %s epid:%d) status:%d %s\n",
++	    (urb == activeUrbList[epid]) ? "active" : "queued",
++	    (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++	    str_type(urb->pipe), epid, urb->status,
++	    (urb_priv->later_data) ? "later-sched" : "");
++
++    tc_finish_urb(hcd, activeUrbList[epid], -ENOENT);
++    ASSERT(activeUrbList[epid] == NULL);
++  }
++
++  /* Finish any queued URBs for this endpoint. There won't be any resubmitions
++     because epid_disabled causes enqueue() to fail for this endpoint */
++  while((urb = urb_list_first(epid)) != NULL) {
++    urb_priv = urb->hcpriv;
++    ASSERT(urb_priv);
++
++    tc_warn("Sync finish %s URB:0x%x[%d] (%s %s epid:%d) status:%d %s\n",
++	    (urb == activeUrbList[epid]) ? "active" : "queued",
++	    (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++	    str_type(urb->pipe), epid, urb->status,
++	    (urb_priv->later_data) ? "later-sched" : "");
++
++    tc_finish_urb(hcd, urb, -ENOENT);
++  }
++  epid_state[epid].disabled = 0;
++  local_irq_restore(flags);
++}
++
++/* free resources associated with an endpoint (called from hcd_driver) */
++static void tc_endpoint_disable(struct usb_hcd *hcd, 
++				struct usb_host_endpoint *ep) {
++  DBFENTER;
++  /* Only free epid if it has been allocated. We get two endpoint_disable
++     requests for ctrl endpoints so ignore the second one */
++  if(ep->hcpriv != NULL) {
++    struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++    int epid = ep_priv->epid;
++    tc_warn("endpoint_disable ep:0x%x ep-priv:0x%x (%s) (epid:%d freed)\n",
++	   (unsigned int)ep, (unsigned int)ep->hcpriv,
++	   endpoint_to_str(&(ep->desc)), epid);
++
++    tc_sync_finish_epid(hcd, epid);
++
++    ASSERT(activeUrbList[epid] == NULL);
++    ASSERT(list_empty(&urb_list[epid]));
++
++    tc_free_epid(ep);
++  } else {
++    tc_dbg("endpoint_disable ep:0x%x ep-priv:0x%x (%s)\n", (unsigned int)ep,
++	   (unsigned int)ep->hcpriv, endpoint_to_str(&(ep->desc)));
++  }
++  DBFEXIT;
++}
++
++//static void tc_finish_urb_later_proc(void *data) {
++static void tc_finish_urb_later_proc(struct work_struct *work) {
++  unsigned long flags;
++  //struct urb_later_data* uld = (struct urb_later_data*)data;
++  struct urb_later_data* uld = container_of(work, struct urb_later_data, ws.work);
++  local_irq_save(flags);
++  if(uld->urb == NULL) {
++    late_dbg("Later finish of URB = NULL (allready finished)\n");
++  } else {
++    struct crisv10_urb_priv* urb_priv = uld->urb->hcpriv;
++    ASSERT(urb_priv);
++    if(urb_priv->urb_num == uld->urb_num) {
++      late_dbg("Later finish of URB:0x%x[%d]\n", (unsigned int)(uld->urb),
++	       urb_priv->urb_num);
++      if(uld->status != uld->urb->status) {
++	errno_dbg("Later-finish URB with status:%d, later-status:%d\n",
++		  uld->urb->status, uld->status);
++      }
++      if(uld != urb_priv->later_data) {
++	panic("Scheduled uld not same as URBs uld\n");
++      }
++      tc_finish_urb(uld->hcd, uld->urb, uld->status);
++    } else {
++      late_warn("Ignoring later finish of URB:0x%x[%d]"
++		", urb_num doesn't match current URB:0x%x[%d]",
++		(unsigned int)(uld->urb), uld->urb_num,
++		(unsigned int)(uld->urb), urb_priv->urb_num);
++    }
++  }
++  local_irq_restore(flags);
++  kmem_cache_free(later_data_cache, uld);
++}
++
++static void tc_finish_urb_later(struct usb_hcd *hcd, struct urb *urb,
++				int status) {
++  struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++  struct urb_later_data* uld;
++
++  ASSERT(urb_priv);
++
++  if(urb_priv->later_data != NULL) {
++    /* Later-finish allready scheduled for this URB, just update status to
++       return when finishing later */
++    errno_dbg("Later-finish schedule change URB status:%d with new"
++	      " status:%d\n", urb_priv->later_data->status, status);
++    
++    urb_priv->later_data->status = status;
++    return;
++  }
++
++  uld = kmem_cache_alloc(later_data_cache, GFP_ATOMIC);
++  ASSERT(uld);
++
++  uld->hcd = hcd;
++  uld->urb = urb;
++  uld->urb_num = urb_priv->urb_num;
++  uld->status = status;
++
++  //INIT_WORK(&uld->ws, tc_finish_urb_later_proc, uld);
++  INIT_DELAYED_WORK(&uld->ws, tc_finish_urb_later_proc);
++  urb_priv->later_data = uld;
++
++  /* Schedule the finishing of the URB to happen later */
++  schedule_delayed_work(&uld->ws, LATER_TIMER_DELAY);
++}
++
++  /* hinko ignore usb_pipeisoc */
++#if 0
++static void tc_finish_isoc_urb(struct usb_hcd *hcd, struct urb *urb,
++			       int status);
++#endif
++
++static void tc_finish_urb(struct usb_hcd *hcd, struct urb *urb, int status) {
++  struct crisv10_hcd* crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++  struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++  int epid;
++  char toggle;
++  int urb_num;
++  unsigned long flags;
++
++  DBFENTER;
++  ASSERT(urb_priv != NULL);
++  epid = urb_priv->epid;
++  urb_num = urb_priv->urb_num;
++
++  if(urb != activeUrbList[epid]) {
++    if(urb_list_entry(urb, epid)) {
++      /* Remove this URB from the list. Only happens when URB are finished
++	 before having been processed (dequeing) */
++      urb_list_del(urb, epid);
++    } else {
++      tc_warn("Finishing of URB:0x%x[%d] neither active or in queue for"
++	      " epid:%d\n", (unsigned int)urb, urb_num, epid);
++    }
++  }
++
++  /* Cancel any pending later-finish of this URB */
++  if(urb_priv->later_data) {
++    urb_priv->later_data->urb = NULL;
++  }
++
++  /* For an IN pipe, we always set the actual length, regardless of whether
++     there was an error or not (which means the device driver can use the data
++     if it wants to). */
++  if(usb_pipein(urb->pipe)) {
++    urb->actual_length = urb_priv->rx_offset;
++  } else {
++    /* Set actual_length for OUT urbs also; the USB mass storage driver seems
++       to want that. */
++    if (status == 0 && urb->status == -EINPROGRESS) {
++      urb->actual_length = urb->transfer_buffer_length;
++    } else {
++      /*  We wouldn't know of any partial writes if there was an error. */
++      urb->actual_length = 0;
++    }
++  }
++
++
++  /* URB status mangling */
++  if(urb->status == -EINPROGRESS) {
++    /* The USB core hasn't changed the status, let's set our finish status */
++    urb->status = status;
++
++    if ((status == 0) && (urb->transfer_flags & URB_SHORT_NOT_OK) &&
++	usb_pipein(urb->pipe) &&
++	(urb->actual_length != urb->transfer_buffer_length)) {
++      /* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's
++	 max length) is to be treated as an error. */
++      errno_dbg("Finishing URB:0x%x[%d] with SHORT_NOT_OK flag and short"
++		" data:%d\n", (unsigned int)urb, urb_num,
++		urb->actual_length);
++      urb->status = -EREMOTEIO;
++    }
++
++    if(urb_priv->urb_state == UNLINK) {
++      /* URB has been requested to be unlinked asynchronously */
++      urb->status = -ECONNRESET;
++      errno_dbg("Fixing unlink status of URB:0x%x[%d] to:%d\n",
++		(unsigned int)urb, urb_num, urb->status);
++    }
++  } else {
++    /* The USB Core wants to signal some error via the URB, pass it through */
++  }
++
++  /* hinko ignore usb_pipeisoc */
++#if 0
++  /* use completely different finish function for Isoc URBs */
++  if(usb_pipeisoc(urb->pipe)) {
++    tc_finish_isoc_urb(hcd, urb, status);
++    return;
++  }
++#endif
++
++  /* Do special unlinking of EPs for Intr traffic */
++  if(usb_pipeint(urb->pipe)) {
++    tc_dma_unlink_intr_urb(urb);
++  }
++
++  /* hinko ignore usb_pipeisoc */
++#if 0
++  /* Release allocated bandwidth for periodic transfers */
++  if(usb_pipeint(urb->pipe) || usb_pipeisoc(urb->pipe))
++    usb_release_bandwidth(urb->dev, urb, 0);
++#endif
++  
++  /* This URB is active on EP */
++  if(urb == activeUrbList[epid]) {
++    /* We need to fiddle with the toggle bits because the hardware doesn't do
++       it for us. */
++    toggle = etrax_epid_get_toggle(epid, usb_pipeout(urb->pipe));
++    usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++		  usb_pipeout(urb->pipe), toggle);
++
++    /* Checks for Ctrl and Bulk EPs */
++    switch(usb_pipetype(urb->pipe)) {
++    case PIPE_BULK:
++      /* Check so Bulk EP realy is disabled before finishing active URB  */
++      ASSERT((TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) ==
++	     IO_STATE(USB_EP_command, enable, no));
++      /* Disable sub-pointer for EP to avoid next tx_interrupt() to
++	 process Bulk EP. */
++      TxBulkEPList[epid].sub = 0;
++      /* No need to wait for the DMA before changing the next pointer.
++	 The modulo NBR_OF_EPIDS isn't actually necessary, since we will never use
++	 the last one (INVALID_EPID) for actual traffic. */
++      TxBulkEPList[epid].next = 
++	virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
++      break;
++    case PIPE_CONTROL:
++      /* Check so Ctrl EP realy is disabled before finishing active URB  */
++      ASSERT((TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) ==
++	     IO_STATE(USB_EP_command, enable, no));
++      /* Disable sub-pointer for EP to avoid next tx_interrupt() to
++	 process Ctrl EP. */
++      TxCtrlEPList[epid].sub = 0;
++      break;
++    }
++  }
++
++  /* Free HC-private URB data*/
++  urb_priv_free(hcd, urb);
++
++  if(urb->status) {
++    errno_dbg("finish_urb (URB:0x%x[%d] %s %s) (data:%d) status:%d\n",
++	      (unsigned int)urb, urb_num, str_dir(urb->pipe),
++	      str_type(urb->pipe), urb->actual_length, urb->status);
++  } else {
++    tc_dbg("finish_urb (URB:0x%x[%d] %s %s) (data:%d) status:%d\n",
++	   (unsigned int)urb, urb_num, str_dir(urb->pipe),
++	   str_type(urb->pipe), urb->actual_length, urb->status);
++  }
++
++  /* If we just finished an active URB, clear active pointer. */
++  if (urb == activeUrbList[epid]) {
++    /* Make URB not active on EP anymore */
++    activeUrbList[epid] = NULL;
++
++    if(urb->status == 0) {
++      /* URB finished sucessfully, process queue to see if there are any more
++	 URBs waiting before we call completion function.*/
++      if(crisv10_hcd->running) {
++	/* Only process queue if USB controller is running */
++	tc_dma_process_queue(epid);
++      } else {
++	tc_warn("No processing of queue for epid:%d, USB Controller not"
++		" running\n", epid);
++      }
++    }
++  }
++
++  /*  Hand the URB from HCD to its USB device driver, using its completion
++      functions */
++//  usb_hcd_giveback_urb (hcd, urb);
++	/**
++	 * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
++	 * @hcd: host controller to which @urb was submitted
++	 * @urb: URB being unlinked
++	 *
++	 * Host controller drivers should call this routine before calling
++	 * usb_hcd_giveback_urb().  The HCD's private spinlock must be held and
++	 * interrupts must be disabled.  The actions carried out here are required
++	 * for URB completion.
++	 */
++  
++  /*hinko link/unlink urb -> ep */
++  //spin_lock(&crisv10_hcd->lock);
++  spin_lock_irqsave(&crisv10_hcd->lock, flags);
++  usb_hcd_unlink_urb_from_ep(hcd, urb);
++  usb_hcd_giveback_urb(hcd, urb, status);
++  //spin_unlock(&crisv10_hcd->lock);
++  spin_unlock_irqrestore(&crisv10_hcd->lock, flags);
++
++  /* Check the queue once more if the URB returned with error, because we
++     didn't do it before the completion function because the specification
++     states that the queue should not restart until all it's unlinked
++     URBs have been fully retired, with the completion functions run */
++  if(crisv10_hcd->running) {
++    /* Only process queue if USB controller is running */
++    tc_dma_process_queue(epid);
++  } else {
++    tc_warn("No processing of queue for epid:%d, USB Controller not running\n",
++	    epid);
++  }
++
++  DBFEXIT;
++}
++
++  /* hinko ignore usb_pipeisoc */
++#if 0
++static void tc_finish_isoc_urb(struct usb_hcd *hcd, struct urb *urb,
++			       int status) {
++  struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++  int epid, i;
++  volatile int timeout = 10000;
++
++  ASSERT(urb_priv);
++  epid = urb_priv->epid;
++
++  ASSERT(usb_pipeisoc(urb->pipe));
++
++  /* Set that all isoc packets have status and length set before
++     completing the urb. */
++  for (i = urb_priv->isoc_packet_counter; i < urb->number_of_packets; i++){
++    urb->iso_frame_desc[i].actual_length = 0;
++    urb->iso_frame_desc[i].status = -EPROTO;
++  }
++
++  /* Check if the URB is currently active (done or error) */
++  if(urb == activeUrbList[epid]) {
++    /* Check if there are another In Isoc URB queued for this epid */
++    if (!list_empty(&urb_list[epid])&& !epid_state[epid].disabled) {
++      /* Move it from queue to active and mark it started so Isoc transfers
++	 won't be interrupted.
++	 All Isoc URBs data transfers are already added to DMA lists so we
++	 don't have to insert anything in DMA lists here. */
++      activeUrbList[epid] = urb_list_first(epid);
++      ((struct crisv10_urb_priv *)(activeUrbList[epid]->hcpriv))->urb_state =
++	STARTED;
++      urb_list_del(activeUrbList[epid], epid);
++
++      if(urb->status) {
++	errno_dbg("finish_isoc_urb (URB:0x%x[%d] %s %s) (%d of %d packets)"
++		  " status:%d, new waiting URB:0x%x[%d]\n",
++		  (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++		  str_type(urb->pipe), urb_priv->isoc_packet_counter,
++		  urb->number_of_packets, urb->status,
++		  (unsigned int)activeUrbList[epid],
++		  ((struct crisv10_urb_priv *)(activeUrbList[epid]->hcpriv))->urb_num);
++      }
++
++    } else { /* No other URB queued for this epid */
++      if(urb->status) {
++	errno_dbg("finish_isoc_urb (URB:0x%x[%d] %s %s) (%d of %d packets)"
++		  " status:%d, no new URB waiting\n",
++		  (unsigned int)urb, urb_priv->urb_num, str_dir(urb->pipe),
++		  str_type(urb->pipe), urb_priv->isoc_packet_counter,
++		  urb->number_of_packets, urb->status);
++      }
++
++      /* Check if EP is still enabled, then shut it down. */
++      if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++	isoc_dbg("Isoc EP enabled for epid:%d, disabling it\n", epid);
++
++	/* Should only occur for In Isoc EPs where SB isn't consumed. */
++	ASSERT(usb_pipein(urb->pipe));
++
++	/* Disable it and wait for it to stop */
++	TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
++	
++	/* Ah, the luxury of busy-wait. */
++	while((*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid])) &&
++	      (timeout-- > 0));
++	if(timeout == 0) {
++	  warn("Timeout while waiting for DMA-TX-Isoc to leave EP for epid:%d\n", epid);
++	}
++      }
++
++      /* Unlink SB to say that epid is finished. */
++      TxIsocEPList[epid].sub = 0;
++      TxIsocEPList[epid].hw_len = 0;
++
++      /* No URB active for EP anymore */
++      activeUrbList[epid] = NULL;
++    }
++  } else { /* Finishing of not active URB (queued up with SBs thought) */
++    isoc_warn("finish_isoc_urb (URB:0x%x %s) (%d of %d packets) status:%d,"
++	      " SB queued but not active\n",
++	      (unsigned int)urb, str_dir(urb->pipe),
++	      urb_priv->isoc_packet_counter, urb->number_of_packets,
++	      urb->status);
++    if(usb_pipeout(urb->pipe)) {
++      /* Finishing of not yet active Out Isoc URB needs unlinking of SBs. */
++      struct USB_SB_Desc *iter_sb, *prev_sb, *next_sb;
++
++      iter_sb = TxIsocEPList[epid].sub ?
++	phys_to_virt(TxIsocEPList[epid].sub) : 0;
++      prev_sb = 0;
++
++      /* SB that is linked before this URBs first SB */
++      while (iter_sb && (iter_sb != urb_priv->first_sb)) {
++	prev_sb = iter_sb;
++	iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
++      }
++
++      if (iter_sb == 0) {
++	/* Unlink of the URB currently being transmitted. */
++	prev_sb = 0;
++	iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;
++      }
++
++      while (iter_sb && (iter_sb != urb_priv->last_sb)) {
++	iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
++      }
++
++      if (iter_sb) {
++	next_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
++      } else {
++	/* This should only happen if the DMA has completed
++	   processing the SB list for this EP while interrupts
++	   are disabled. */
++	isoc_dbg("Isoc urb not found, already sent?\n");
++	next_sb = 0;
++      }
++      if (prev_sb) {
++	prev_sb->next = next_sb ? virt_to_phys(next_sb) : 0;
++      } else {
++	TxIsocEPList[epid].sub = next_sb ? virt_to_phys(next_sb) : 0;
++      }
++    }
++  }
++
++  /* Free HC-private URB data*/
++  urb_priv_free(hcd, urb);
++
++  usb_release_bandwidth(urb->dev, urb, 0);
++
++  /*  Hand the URB from HCD to its USB device driver, using its completion
++      functions */
++  usb_hcd_giveback_urb (hcd, urb);
++}
++#endif
++
++static __u32 urb_num = 0;
++
++/* allocate and initialize URB private data */
++static int urb_priv_create(struct usb_hcd *hcd, struct urb *urb, int epid,
++			   int mem_flags) {
++  struct crisv10_urb_priv *urb_priv;
++  
++  urb_priv = kmalloc(sizeof *urb_priv, mem_flags);
++  if (!urb_priv)
++    return -ENOMEM;
++  memset(urb_priv, 0, sizeof *urb_priv);
++
++  urb_priv->epid = epid;
++  urb_priv->urb_state = NOT_STARTED;
++
++  urb->hcpriv = urb_priv;
++  /* Assign URB a sequence number, and increment counter */
++  urb_priv->urb_num = urb_num;
++  urb_num++;
++  return 0;
++}
++
++/* free URB private data */
++static void urb_priv_free(struct usb_hcd *hcd, struct urb *urb) {
++  int i;
++  struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++  ASSERT(urb_priv != 0);
++
++  /* Check it has any SBs linked that needs to be freed*/
++  if(urb_priv->first_sb != NULL) {
++    struct USB_SB_Desc *next_sb, *first_sb, *last_sb;
++    int i = 0;
++    first_sb = urb_priv->first_sb;
++    last_sb = urb_priv->last_sb;
++    ASSERT(last_sb);
++    while(first_sb != last_sb) {
++      next_sb = (struct USB_SB_Desc *)phys_to_virt(first_sb->next);
++      kmem_cache_free(usb_desc_cache, first_sb);
++      first_sb = next_sb;
++      i++;
++    }
++    kmem_cache_free(usb_desc_cache, last_sb);
++    i++;
++  }
++
++  /* Check if it has any EPs in its Intr pool that also needs to be freed */
++  if(urb_priv->intr_ep_pool_length > 0) {
++    for(i = 0; i < urb_priv->intr_ep_pool_length; i++) {
++      kfree(urb_priv->intr_ep_pool[i]);
++    }
++    /*
++    tc_dbg("Freed %d EPs from URB:0x%x EP pool\n",
++	     urb_priv->intr_ep_pool_length, (unsigned int)urb);
++    */
++  }
++
++  kfree(urb_priv);
++  urb->hcpriv = NULL;
++}
++
++static int ep_priv_create(struct usb_host_endpoint *ep, int mem_flags) {
++  struct crisv10_ep_priv *ep_priv;
++  
++  ep_priv = kmalloc(sizeof *ep_priv, mem_flags);
++  if (!ep_priv)
++    return -ENOMEM;
++  memset(ep_priv, 0, sizeof *ep_priv);
++
++  ep->hcpriv = ep_priv;
++  return 0;
++}
++
++static void ep_priv_free(struct usb_host_endpoint *ep) {
++  struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++  ASSERT(ep_priv);
++  kfree(ep_priv);
++  ep->hcpriv = NULL;
++}
++
++/* EPID handling functions, managing EP-list in Etrax through wrappers */
++/* ------------------------------------------------------------------- */
++
++/* Sets up a new EPID for an endpoint or returns existing if found */
++//static int tc_setup_epid(struct usb_host_endpoint *ep, struct urb *urb,
++//			 int mem_flags) {
++static int tc_setup_epid(struct urb *urb, int mem_flags)
++{
++  int epid;
++  char devnum, endpoint, out_traffic, slow;
++  int maxlen;
++  __u32 epid_data;
++  struct usb_host_endpoint *ep = urb->ep;
++  struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++  
++  DBFENTER;
++  
++  /* Check if a valid epid already is setup for this endpoint */
++  if(ep_priv != NULL) {
++    return ep_priv->epid;
++  }
++
++  /* We must find and initiate a new epid for this urb. */
++  epid = tc_allocate_epid();
++  
++  if (epid == -1) {
++    /* Failed to allocate a new epid. */
++    DBFEXIT;
++    return epid;
++  }
++  
++  /* We now have a new epid to use. Claim it. */
++  epid_state[epid].inuse = 1;
++  
++  /* Init private data for new endpoint */
++  if(ep_priv_create(ep, mem_flags) != 0) {
++    return -ENOMEM;
++  }
++  ep_priv = ep->hcpriv;
++  ep_priv->epid = epid;
++
++  devnum = usb_pipedevice(urb->pipe);
++  endpoint = usb_pipeendpoint(urb->pipe);
++  slow = (urb->dev->speed == USB_SPEED_LOW);
++  maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
++
++  if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
++    /* We want both IN and OUT control traffic to be put on the same
++       EP/SB list. */
++    out_traffic = 1;
++  } else {
++    out_traffic = usb_pipeout(urb->pipe);
++  }
++    
++  if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++    epid_data = IO_STATE(R_USB_EPT_DATA_ISO, valid, yes) |
++      /* FIXME: Change any to the actual port? */
++      IO_STATE(R_USB_EPT_DATA_ISO, port, any) |
++      IO_FIELD(R_USB_EPT_DATA_ISO, max_len, maxlen) |
++      IO_FIELD(R_USB_EPT_DATA_ISO, ep, endpoint) |
++      IO_FIELD(R_USB_EPT_DATA_ISO, dev, devnum);
++    etrax_epid_iso_set(epid, epid_data);
++  } else {
++    epid_data = IO_STATE(R_USB_EPT_DATA, valid, yes) |
++      IO_FIELD(R_USB_EPT_DATA, low_speed, slow) |
++      /* FIXME: Change any to the actual port? */
++      IO_STATE(R_USB_EPT_DATA, port, any) |
++      IO_FIELD(R_USB_EPT_DATA, max_len, maxlen) |
++      IO_FIELD(R_USB_EPT_DATA, ep, endpoint) |
++      IO_FIELD(R_USB_EPT_DATA, dev, devnum);
++    etrax_epid_set(epid, epid_data);
++  }
++  
++  epid_state[epid].out_traffic = out_traffic;
++  epid_state[epid].type = usb_pipetype(urb->pipe);
++
++  tc_warn("Setting up ep:0x%x epid:%d (addr:%d endp:%d max_len:%d %s %s %s)\n",
++	  (unsigned int)ep, epid, devnum, endpoint, maxlen,
++	  str_type(urb->pipe), out_traffic ? "out" : "in",
++	  slow ? "low" : "full");
++
++  /* Enable Isoc eof interrupt if we set up the first Isoc epid */
++  if(usb_pipeisoc(urb->pipe)) {
++    isoc_epid_counter++;
++    if(isoc_epid_counter == 1) {
++      isoc_warn("Enabled Isoc eof interrupt\n");
++      *R_USB_IRQ_MASK_SET |= IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set);
++    }
++  }
++
++  DBFEXIT;
++  return epid;
++}
++
++static void tc_free_epid(struct usb_host_endpoint *ep) {
++  unsigned long flags;
++  struct crisv10_ep_priv *ep_priv = ep->hcpriv;
++  int epid;
++  volatile int timeout = 10000;
++
++  DBFENTER;
++
++  if (ep_priv == NULL) {
++    tc_warn("Trying to free unused epid on ep:0x%x\n", (unsigned int)ep);
++    DBFEXIT;
++    return;
++  }
++
++  epid = ep_priv->epid;
++
++  /* Disable Isoc eof interrupt if we free the last Isoc epid */
++  if(epid_isoc(epid)) {
++    ASSERT(isoc_epid_counter > 0);
++    isoc_epid_counter--;
++    if(isoc_epid_counter == 0) {
++      *R_USB_IRQ_MASK_SET &= ~IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set);
++      isoc_warn("Disabled Isoc eof interrupt\n");
++    }
++  }
++
++  /* Take lock manualy instead of in epid_x_x wrappers,
++     because we need to be polling here */
++  spin_lock_irqsave(&etrax_epid_lock, flags);
++  
++  *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
++  nop();
++  while((*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) &&
++	(timeout-- > 0));
++  if(timeout == 0) {
++    warn("Timeout while waiting for epid:%d to drop hold\n", epid);
++  }
++  /* This will, among other things, set the valid field to 0. */
++  *R_USB_EPT_DATA = 0;
++  spin_unlock_irqrestore(&etrax_epid_lock, flags);
++  
++  /* Free resource in software state info list */
++  epid_state[epid].inuse = 0;
++
++  /* Free private endpoint data */
++  ep_priv_free(ep);
++  
++  DBFEXIT;
++}
++
++static int tc_allocate_epid(void) {
++  int i;
++  DBFENTER;
++  for (i = 0; i < NBR_OF_EPIDS; i++) {
++    if (!epid_inuse(i)) {
++      DBFEXIT;
++      return i;
++    }
++  }
++  
++  tc_warn("Found no free epids\n");
++  DBFEXIT;
++  return -1;
++}
++
++
++/* Wrappers around the list functions (include/linux/list.h). */
++/* ---------------------------------------------------------- */
++static inline int __urb_list_empty(int epid) {
++  int retval;
++  retval = list_empty(&urb_list[epid]);
++  return retval;
++}
++
++/* Returns first urb for this epid, or NULL if list is empty. */
++static inline struct urb *urb_list_first(int epid) {
++  unsigned long flags;
++  struct urb *first_urb = 0;
++  spin_lock_irqsave(&urb_list_lock, flags);
++  if (!__urb_list_empty(epid)) {
++    /* Get the first urb (i.e. head->next). */
++    urb_entry_t *urb_entry = list_entry((&urb_list[epid])->next, urb_entry_t, list);
++    first_urb = urb_entry->urb;
++  }
++  spin_unlock_irqrestore(&urb_list_lock, flags);
++  return first_urb;
++}
++
++/* Adds an urb_entry last in the list for this epid. */
++static inline void urb_list_add(struct urb *urb, int epid, int mem_flags) {
++  unsigned long flags;
++  urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), mem_flags);
++  ASSERT(urb_entry);
++  
++  urb_entry->urb = urb;
++  spin_lock_irqsave(&urb_list_lock, flags);
++  list_add_tail(&urb_entry->list, &urb_list[epid]);
++  spin_unlock_irqrestore(&urb_list_lock, flags);
++}
++
++/* Search through the list for an element that contains this urb. (The list
++   is expected to be short and the one we are about to delete will often be
++   the first in the list.)
++   Should be protected by spin_locks in calling function */
++static inline urb_entry_t *__urb_list_entry(struct urb *urb, int epid) {
++  struct list_head *entry;
++  struct list_head *tmp;
++  urb_entry_t *urb_entry;
++  
++  list_for_each_safe(entry, tmp, &urb_list[epid]) {
++    urb_entry = list_entry(entry, urb_entry_t, list);
++    ASSERT(urb_entry);
++    ASSERT(urb_entry->urb);
++    
++    if (urb_entry->urb == urb) {
++      return urb_entry;
++    }
++  }
++  return 0;
++}
++
++/* Same function as above but for global use. Protects list by spinlock */
++static inline urb_entry_t *urb_list_entry(struct urb *urb, int epid) {
++  unsigned long flags;
++  urb_entry_t *urb_entry;
++  spin_lock_irqsave(&urb_list_lock, flags);
++  urb_entry = __urb_list_entry(urb, epid);
++  spin_unlock_irqrestore(&urb_list_lock, flags);
++  return (urb_entry);
++}
++
++/* Delete an urb from the list. */
++static inline void urb_list_del(struct urb *urb, int epid) {
++  unsigned long flags;
++  urb_entry_t *urb_entry;
++
++  /* Delete entry and free. */
++  spin_lock_irqsave(&urb_list_lock, flags);
++  urb_entry = __urb_list_entry(urb, epid);
++  ASSERT(urb_entry);
++
++  list_del(&urb_entry->list);
++  spin_unlock_irqrestore(&urb_list_lock, flags);
++  kfree(urb_entry);
++}
++
++/* Move an urb to the end of the list. */
++static inline void urb_list_move_last(struct urb *urb, int epid) {
++  unsigned long flags;
++  urb_entry_t *urb_entry;
++  
++  spin_lock_irqsave(&urb_list_lock, flags);
++  urb_entry = __urb_list_entry(urb, epid);
++  ASSERT(urb_entry);
++
++  list_del(&urb_entry->list);
++  list_add_tail(&urb_entry->list, &urb_list[epid]);
++  spin_unlock_irqrestore(&urb_list_lock, flags);
++}
++
++/* Get the next urb in the list. */
++static inline struct urb *urb_list_next(struct urb *urb, int epid) {
++  unsigned long flags;
++  urb_entry_t *urb_entry;
++
++  spin_lock_irqsave(&urb_list_lock, flags);
++  urb_entry = __urb_list_entry(urb, epid);
++  ASSERT(urb_entry);
++
++  if (urb_entry->list.next != &urb_list[epid]) {
++    struct list_head *elem = urb_entry->list.next;
++    urb_entry = list_entry(elem, urb_entry_t, list);
++    spin_unlock_irqrestore(&urb_list_lock, flags);
++    return urb_entry->urb;
++  } else {
++    spin_unlock_irqrestore(&urb_list_lock, flags);
++    return NULL;
++  }
++}
++
++struct USB_EP_Desc* create_ep(int epid, struct USB_SB_Desc* sb_desc,
++			      int mem_flags) {
++  struct USB_EP_Desc *ep_desc;
++  ep_desc = (struct USB_EP_Desc *) kmem_cache_alloc(usb_desc_cache, mem_flags);
++  if(ep_desc == NULL)
++    return NULL;
++  memset(ep_desc, 0, sizeof(struct USB_EP_Desc));
++
++  ep_desc->hw_len = 0;
++  ep_desc->command = (IO_FIELD(USB_EP_command, epid, epid) |
++		      IO_STATE(USB_EP_command, enable, yes));
++  if(sb_desc == NULL) {
++    ep_desc->sub = 0;
++  } else {
++    ep_desc->sub = virt_to_phys(sb_desc);
++  }
++  return ep_desc;
++}
++
++#define TT_ZOUT  0
++#define TT_IN    1
++#define TT_OUT   2
++#define TT_SETUP 3
++
++#define CMD_EOL  IO_STATE(USB_SB_command, eol, yes)
++#define CMD_INTR IO_STATE(USB_SB_command, intr, yes)
++#define CMD_FULL IO_STATE(USB_SB_command, full, yes)
++
++/* Allocation and setup of a generic SB. Used to create SETUP, OUT and ZOUT
++   SBs. Also used by create_sb_in() to avoid same allocation procedure at two
++   places */
++struct USB_SB_Desc* create_sb(struct USB_SB_Desc* sb_prev, int tt, void* data,
++			      int datalen, int mem_flags) {
++  struct USB_SB_Desc *sb_desc;
++  sb_desc = (struct USB_SB_Desc*)kmem_cache_alloc(usb_desc_cache, mem_flags);
++  if(sb_desc == NULL)
++    return NULL;
++  memset(sb_desc, 0, sizeof(struct USB_SB_Desc));
++
++  sb_desc->command = IO_FIELD(USB_SB_command, tt, tt) |
++                     IO_STATE(USB_SB_command, eot, yes);
++
++  sb_desc->sw_len = datalen;
++  if(data != NULL) {
++    sb_desc->buf = virt_to_phys(data);
++  } else {
++    sb_desc->buf = 0;
++  }
++  if(sb_prev != NULL) {
++    sb_prev->next = virt_to_phys(sb_desc);
++  }
++  return sb_desc;
++}
++
++/* Creates a copy of an existing SB by allocation space for it and copy
++   settings */
++struct USB_SB_Desc* create_sb_copy(struct USB_SB_Desc* sb_orig, int mem_flags) {
++  struct USB_SB_Desc *sb_desc;
++  sb_desc = (struct USB_SB_Desc*)kmem_cache_alloc(usb_desc_cache, mem_flags);
++  if(sb_desc == NULL)
++    return NULL;
++
++  memcpy(sb_desc, sb_orig, sizeof(struct USB_SB_Desc));
++  return sb_desc;
++}
++
++/* A specific create_sb function for creation of in SBs. This is due to
++   that datalen in In SBs shows how many packets we are expecting. It also
++   sets up the rem field to show if how many bytes we expect in last packet
++   if it's not a full one */
++struct USB_SB_Desc* create_sb_in(struct USB_SB_Desc* sb_prev, int datalen,
++				 int maxlen, int mem_flags) {
++  struct USB_SB_Desc *sb_desc;
++  sb_desc = create_sb(sb_prev, TT_IN, NULL,
++		      datalen ? (datalen - 1) / maxlen + 1 : 0, mem_flags);
++  if(sb_desc == NULL)
++    return NULL;
++  sb_desc->command |= IO_FIELD(USB_SB_command, rem, datalen % maxlen);
++  return sb_desc;
++}
++
++void set_sb_cmds(struct USB_SB_Desc *sb_desc, __u16 flags) {
++  sb_desc->command |= flags;
++}
++
++int create_sb_for_urb(struct urb *urb, int mem_flags) {
++  int is_out = !usb_pipein(urb->pipe);
++  int type = usb_pipetype(urb->pipe);
++  int maxlen = usb_maxpacket(urb->dev, urb->pipe, is_out);
++  int buf_len = urb->transfer_buffer_length;
++  void *buf = buf_len > 0 ? urb->transfer_buffer : NULL;
++  struct USB_SB_Desc *sb_desc = NULL;
++
++  struct crisv10_urb_priv *urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++  ASSERT(urb_priv != NULL);
++
++  switch(type) {
++  case PIPE_CONTROL:
++    /* Setup stage */
++    sb_desc = create_sb(NULL, TT_SETUP, urb->setup_packet, 8, mem_flags);
++    if(sb_desc == NULL)
++      return -ENOMEM;
++    set_sb_cmds(sb_desc, CMD_FULL);
++
++    /* Attach first SB to URB */
++    urb_priv->first_sb = sb_desc;    
++
++    if (is_out) { /* Out Control URB */
++      /* If this Control OUT transfer has an optional data stage we add
++	 an OUT token before the mandatory IN (status) token */
++      if ((buf_len > 0) && buf) {
++	sb_desc = create_sb(sb_desc, TT_OUT, buf, buf_len, mem_flags);
++	if(sb_desc == NULL)
++	  return -ENOMEM;
++	set_sb_cmds(sb_desc, CMD_FULL);
++      }
++
++      /* Status stage */
++      /* The data length has to be exactly 1. This is due to a requirement
++         of the USB specification that a host must be prepared to receive
++         data in the status phase */
++      sb_desc = create_sb(sb_desc, TT_IN, NULL, 1, mem_flags);
++      if(sb_desc == NULL)
++	return -ENOMEM;
++    } else { /* In control URB */
++      /* Data stage */
++      sb_desc = create_sb_in(sb_desc, buf_len, maxlen, mem_flags);
++      if(sb_desc == NULL)
++	return -ENOMEM;
++
++      /* Status stage */
++      /* Read comment at zout_buffer declaration for an explanation to this. */
++      sb_desc = create_sb(sb_desc, TT_ZOUT, &zout_buffer[0], 1, mem_flags);
++      if(sb_desc == NULL)
++	return -ENOMEM;
++      /* Set descriptor interrupt flag for in URBs so we can finish URB after
++         zout-packet has been sent */
++      set_sb_cmds(sb_desc, CMD_INTR | CMD_FULL);
++    }
++    /* Set end-of-list flag in last SB */
++    set_sb_cmds(sb_desc, CMD_EOL);
++    /* Attach last SB to URB */
++    urb_priv->last_sb = sb_desc;
++    break;
++
++  case PIPE_BULK:
++    if (is_out) { /* Out Bulk URB */
++      sb_desc = create_sb(NULL, TT_OUT, buf, buf_len, mem_flags);
++      if(sb_desc == NULL)
++	return -ENOMEM;
++      /* The full field is set to yes, even if we don't actually check that
++	 this is a full-length transfer (i.e., that transfer_buffer_length %
++	 maxlen = 0).
++	 Setting full prevents the USB controller from sending an empty packet
++	 in that case.  However, if URB_ZERO_PACKET was set we want that. */
++      if (!(urb->transfer_flags & URB_ZERO_PACKET)) {
++	set_sb_cmds(sb_desc, CMD_FULL);
++      }
++    } else { /* In Bulk URB */
++      sb_desc = create_sb_in(NULL, buf_len, maxlen, mem_flags);
++      if(sb_desc == NULL)
++	return -ENOMEM;
++    }
++    /* Set end-of-list flag for last SB */
++    set_sb_cmds(sb_desc, CMD_EOL);
++
++    /* Attach SB to URB */
++    urb_priv->first_sb = sb_desc;
++    urb_priv->last_sb = sb_desc;
++    break;
++
++  case PIPE_INTERRUPT:
++    if(is_out) { /* Out Intr URB */
++      sb_desc = create_sb(NULL, TT_OUT, buf, buf_len, mem_flags);
++      if(sb_desc == NULL)
++	return -ENOMEM;
++
++      /* The full field is set to yes, even if we don't actually check that
++	 this is a full-length transfer (i.e., that transfer_buffer_length %
++	 maxlen = 0).
++	 Setting full prevents the USB controller from sending an empty packet
++	 in that case.  However, if URB_ZERO_PACKET was set we want that. */
++      if (!(urb->transfer_flags & URB_ZERO_PACKET)) {
++	set_sb_cmds(sb_desc, CMD_FULL);
++      }
++      /* Only generate TX interrupt if it's a Out URB*/
++      set_sb_cmds(sb_desc, CMD_INTR);
++
++    } else { /* In Intr URB */
++      sb_desc = create_sb_in(NULL, buf_len, maxlen, mem_flags);
++      if(sb_desc == NULL)
++	return -ENOMEM;
++    }
++    /* Set end-of-list flag for last SB */
++    set_sb_cmds(sb_desc, CMD_EOL);
++
++    /* Attach SB to URB */
++    urb_priv->first_sb = sb_desc;
++    urb_priv->last_sb = sb_desc;
++
++    break;
++  case PIPE_ISOCHRONOUS:
++    if(is_out) { /* Out Isoc URB */
++      int i;
++      if(urb->number_of_packets == 0) {
++	tc_err("Can't create SBs for Isoc URB with zero packets\n");
++	return -EPIPE;
++      }
++      /* Create one SB descriptor for each packet and link them together. */
++      for(i = 0; i < urb->number_of_packets; i++) {
++	if (urb->iso_frame_desc[i].length > 0) {
++
++	  sb_desc = create_sb(sb_desc, TT_OUT, urb->transfer_buffer +
++			      urb->iso_frame_desc[i].offset,
++			      urb->iso_frame_desc[i].length, mem_flags);
++	  if(sb_desc == NULL)
++	    return -ENOMEM;
++
++	  /* Check if it's a full length packet */
++	  if (urb->iso_frame_desc[i].length ==
++	      usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
++	    set_sb_cmds(sb_desc, CMD_FULL);
++	  }
++	  
++	} else { /* zero length packet */
++	  sb_desc = create_sb(sb_desc, TT_ZOUT, &zout_buffer[0], 1, mem_flags);
++	  if(sb_desc == NULL)
++	    return -ENOMEM;
++	  set_sb_cmds(sb_desc, CMD_FULL);
++	}
++	/* Attach first SB descriptor to URB */
++	if (i == 0) {
++	  urb_priv->first_sb = sb_desc;
++	}
++      }
++      /* Set interrupt and end-of-list flags in last SB */
++      set_sb_cmds(sb_desc, CMD_INTR | CMD_EOL);
++      /* Attach last SB descriptor to URB */
++      urb_priv->last_sb = sb_desc;
++      tc_dbg("Created %d out SBs for Isoc URB:0x%x\n",
++	       urb->number_of_packets, (unsigned int)urb);
++    } else { /* In Isoc URB */
++      /* Actual number of packets is not relevant for periodic in traffic as
++	 long as it is more than zero.  Set to 1 always. */
++      sb_desc = create_sb(sb_desc, TT_IN, NULL, 1, mem_flags);
++      if(sb_desc == NULL)
++	return -ENOMEM;
++      /* Set end-of-list flags for SB */
++      set_sb_cmds(sb_desc, CMD_EOL);
++
++      /* Attach SB to URB */
++      urb_priv->first_sb = sb_desc;
++      urb_priv->last_sb = sb_desc;
++    }
++    break;
++  default:
++    tc_err("Unknown pipe-type\n");
++    return -EPIPE;
++    break;
++  }
++  return 0;
++}
++
++int init_intr_urb(struct urb *urb, int mem_flags) {
++  struct crisv10_urb_priv *urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++  struct USB_EP_Desc* ep_desc;
++  int interval;
++  int i;
++  int ep_count;
++
++  ASSERT(urb_priv != NULL);
++  ASSERT(usb_pipeint(urb->pipe));
++  /* We can't support interval longer than amount of eof descriptors in
++     TxIntrEPList */
++  if(urb->interval > MAX_INTR_INTERVAL) {
++    tc_err("Interrupt interval %dms too big (max: %dms)\n", urb->interval,
++	   MAX_INTR_INTERVAL);
++    return -EINVAL;
++  }
++
++  /* We assume that the SB descriptors already have been setup */
++  ASSERT(urb_priv->first_sb != NULL);
++
++  /* Round of the interval to 2^n, it is obvious that this code favours
++     smaller numbers, but that is actually a good thing */
++  /* FIXME: The "rounding error" for larger intervals will be quite
++     large. For in traffic this shouldn't be a problem since it will only
++     mean that we "poll" more often. */
++  interval = urb->interval;
++  for (i = 0; interval; i++) {
++    interval = interval >> 1;
++  }
++  urb_priv->interval = 1 << (i - 1);
++
++  /* We can only have max interval for Out Interrupt due to that we can only
++     handle one linked in EP for a certain epid in the Intr descr array at the
++     time. The USB Controller in the Etrax 100LX continues to process Intr EPs
++     so we have no way of knowing which one that caused the actual transfer if
++     we have several linked in. */
++  if(usb_pipeout(urb->pipe)) {
++    urb_priv->interval = MAX_INTR_INTERVAL;
++  }
++
++  /* Calculate amount of EPs needed */
++  ep_count = MAX_INTR_INTERVAL / urb_priv->interval;
++
++  for(i = 0; i < ep_count; i++) {
++    ep_desc = create_ep(urb_priv->epid, urb_priv->first_sb, mem_flags);
++    if(ep_desc == NULL) {
++      /* Free any descriptors that we may have allocated before failure */
++      while(i > 0) {
++	i--;
++	kfree(urb_priv->intr_ep_pool[i]);
++      }
++      return -ENOMEM;
++    }
++    urb_priv->intr_ep_pool[i] = ep_desc;
++  }
++  urb_priv->intr_ep_pool_length = ep_count;
++  return 0;
++}
++
++/* DMA RX/TX functions */
++/* ----------------------- */
++
++static void tc_dma_init_rx_list(void) {
++  int i;
++
++  /* Setup descriptor list except last one */
++  for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
++    RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
++    RxDescList[i].command = 0;
++    RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]);
++    RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
++    RxDescList[i].hw_len = 0;
++    RxDescList[i].status = 0;
++    
++    /* DMA IN cache bug. (struct etrax_dma_descr has the same layout as
++       USB_IN_Desc for the relevant fields.) */
++    prepare_rx_descriptor((struct etrax_dma_descr*)&RxDescList[i]);
++    
++  }
++  /* Special handling of last descriptor */
++  RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
++  RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes);
++  RxDescList[i].next = virt_to_phys(&RxDescList[0]);
++  RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
++  RxDescList[i].hw_len = 0;
++  RxDescList[i].status = 0;
++  
++  /* Setup list pointers that show progress in list */
++  myNextRxDesc = &RxDescList[0];
++  myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
++  
++  flush_etrax_cache();
++  /* Point DMA to first descriptor in list and start it */
++  *R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc);
++  *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start);
++}
++
++
++static void tc_dma_init_tx_bulk_list(void) {
++  int i;
++  volatile struct USB_EP_Desc *epDescr;
++
++  for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
++    epDescr = &(TxBulkEPList[i]);
++    CHECK_ALIGN(epDescr);
++    epDescr->hw_len = 0;
++    epDescr->command = IO_FIELD(USB_EP_command, epid, i);
++    epDescr->sub = 0;
++    epDescr->next = virt_to_phys(&TxBulkEPList[i + 1]);
++
++    /* Initiate two EPs, disabled and with the eol flag set. No need for any
++       preserved epid. */
++    
++    /* The first one has the intr flag set so we get an interrupt when the DMA
++       channel is about to become disabled. */
++    CHECK_ALIGN(&TxBulkDummyEPList[i][0]);
++    TxBulkDummyEPList[i][0].hw_len = 0;
++    TxBulkDummyEPList[i][0].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
++				       IO_STATE(USB_EP_command, eol, yes) |
++				       IO_STATE(USB_EP_command, intr, yes));
++    TxBulkDummyEPList[i][0].sub = 0;
++    TxBulkDummyEPList[i][0].next = virt_to_phys(&TxBulkDummyEPList[i][1]);
++    
++    /* The second one. */
++    CHECK_ALIGN(&TxBulkDummyEPList[i][1]);
++    TxBulkDummyEPList[i][1].hw_len = 0;
++    TxBulkDummyEPList[i][1].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
++				       IO_STATE(USB_EP_command, eol, yes));
++    TxBulkDummyEPList[i][1].sub = 0;
++    /* The last dummy's next pointer is the same as the current EP's next pointer. */
++    TxBulkDummyEPList[i][1].next = virt_to_phys(&TxBulkEPList[i + 1]);
++  }
++
++  /* Special handling of last descr in list, make list circular */
++  epDescr = &TxBulkEPList[i];
++  CHECK_ALIGN(epDescr);
++  epDescr->hw_len = 0;
++  epDescr->command = IO_STATE(USB_EP_command, eol, yes) |
++    IO_FIELD(USB_EP_command, epid, i);
++  epDescr->sub = 0;
++  epDescr->next = virt_to_phys(&TxBulkEPList[0]);
++  
++  /* Init DMA sub-channel pointers to last item in each list */
++  *R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[i]);
++  /* No point in starting the bulk channel yet.
++   *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */
++}
++
++static void tc_dma_init_tx_ctrl_list(void) {
++  int i;
++  volatile struct USB_EP_Desc *epDescr;
++
++  for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
++    epDescr = &(TxCtrlEPList[i]);
++    CHECK_ALIGN(epDescr);
++    epDescr->hw_len = 0;
++    epDescr->command = IO_FIELD(USB_EP_command, epid, i);
++    epDescr->sub = 0;
++    epDescr->next = virt_to_phys(&TxCtrlEPList[i + 1]);
++  }
++  /* Special handling of last descr in list, make list circular */
++  epDescr = &TxCtrlEPList[i];
++  CHECK_ALIGN(epDescr);
++  epDescr->hw_len = 0;
++  epDescr->command = IO_STATE(USB_EP_command, eol, yes) |
++    IO_FIELD(USB_EP_command, epid, i);
++  epDescr->sub = 0;
++  epDescr->next = virt_to_phys(&TxCtrlEPList[0]);
++  
++  /* Init DMA sub-channel pointers to last item in each list */
++  *R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[i]);
++  /* No point in starting the ctrl channel yet.
++   *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */
++}
++
++
++static void tc_dma_init_tx_intr_list(void) {
++  int i;
++
++  TxIntrSB_zout.sw_len = 1;
++  TxIntrSB_zout.next = 0;
++  TxIntrSB_zout.buf = virt_to_phys(&zout_buffer[0]);
++  TxIntrSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
++			   IO_STATE(USB_SB_command, tt, zout) |
++			   IO_STATE(USB_SB_command, full, yes) |
++			   IO_STATE(USB_SB_command, eot, yes) |
++			   IO_STATE(USB_SB_command, eol, yes));
++  
++  for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) {
++    CHECK_ALIGN(&TxIntrEPList[i]);
++    TxIntrEPList[i].hw_len = 0;
++    TxIntrEPList[i].command =
++      (IO_STATE(USB_EP_command, eof, yes) |
++       IO_STATE(USB_EP_command, enable, yes) |
++       IO_FIELD(USB_EP_command, epid, INVALID_EPID));
++    TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
++    TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[i + 1]);
++  }
++
++  /* Special handling of last descr in list, make list circular */
++  CHECK_ALIGN(&TxIntrEPList[i]);
++  TxIntrEPList[i].hw_len = 0;
++  TxIntrEPList[i].command =
++    (IO_STATE(USB_EP_command, eof, yes) |
++     IO_STATE(USB_EP_command, eol, yes) |
++     IO_STATE(USB_EP_command, enable, yes) |
++     IO_FIELD(USB_EP_command, epid, INVALID_EPID));
++  TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
++  TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[0]);
++
++  intr_dbg("Initiated Intr EP descriptor list\n");
++
++
++  /* Connect DMA 8 sub-channel 2 to first in list */
++  *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]);
++}
++
++static void tc_dma_init_tx_isoc_list(void) {
++  int i;
++
++  DBFENTER;
++
++  /* Read comment at zout_buffer declaration for an explanation to this. */
++  TxIsocSB_zout.sw_len = 1;
++  TxIsocSB_zout.next = 0;
++  TxIsocSB_zout.buf = virt_to_phys(&zout_buffer[0]);
++  TxIsocSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
++			   IO_STATE(USB_SB_command, tt, zout) |
++			   IO_STATE(USB_SB_command, full, yes) |
++			   IO_STATE(USB_SB_command, eot, yes) |
++			   IO_STATE(USB_SB_command, eol, yes));
++
++  /* The last isochronous EP descriptor is a dummy. */
++  for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
++    CHECK_ALIGN(&TxIsocEPList[i]);
++    TxIsocEPList[i].hw_len = 0;
++    TxIsocEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
++    TxIsocEPList[i].sub = 0;
++    TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[i + 1]);
++  }
++
++  CHECK_ALIGN(&TxIsocEPList[i]);
++  TxIsocEPList[i].hw_len = 0;
++
++  /* Must enable the last EP descr to get eof interrupt. */
++  TxIsocEPList[i].command = (IO_STATE(USB_EP_command, enable, yes) |
++			     IO_STATE(USB_EP_command, eof, yes) |
++			     IO_STATE(USB_EP_command, eol, yes) |
++			     IO_FIELD(USB_EP_command, epid, INVALID_EPID));
++  TxIsocEPList[i].sub = virt_to_phys(&TxIsocSB_zout);
++  TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[0]);
++
++  *R_DMA_CH8_SUB3_EP = virt_to_phys(&TxIsocEPList[0]);
++  *R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
++}
++
++static int tc_dma_init(struct usb_hcd *hcd) {
++  tc_dma_init_rx_list();
++  tc_dma_init_tx_bulk_list();
++  tc_dma_init_tx_ctrl_list();
++  tc_dma_init_tx_intr_list();
++  tc_dma_init_tx_isoc_list();
++
++  if (cris_request_dma(USB_TX_DMA_NBR,
++		       "ETRAX 100LX built-in USB (Tx)",
++		       DMA_VERBOSE_ON_ERROR,
++		       dma_usb)) {
++    err("Could not allocate DMA ch 8 for USB");
++    return -EBUSY;
++  }
++ 	
++  if (cris_request_dma(USB_RX_DMA_NBR,
++		       "ETRAX 100LX built-in USB (Rx)",
++		       DMA_VERBOSE_ON_ERROR,
++		       dma_usb)) {
++    err("Could not allocate DMA ch 9 for USB");
++    return -EBUSY;
++  }
++
++  *R_IRQ_MASK2_SET =
++    /* Note that these interrupts are not used. */
++    IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) |
++    /* Sub channel 1 (ctrl) descr. interrupts are used. */
++    IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) |
++    IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) |
++    /* Sub channel 3 (isoc) descr. interrupts are used. */
++    IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set);
++  
++  /* Note that the dma9_descr interrupt is not used. */
++  *R_IRQ_MASK2_SET =
++    IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) |
++    IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
++
++  if (request_irq(ETRAX_USB_RX_IRQ, tc_dma_rx_interrupt, 0,
++		  "ETRAX 100LX built-in USB (Rx)", hcd)) {
++    err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ);
++    return -EBUSY;
++  }
++  
++  if (request_irq(ETRAX_USB_TX_IRQ, tc_dma_tx_interrupt, 0,
++		  "ETRAX 100LX built-in USB (Tx)", hcd)) {
++    err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ);
++    return -EBUSY;
++  }
++
++  return 0;
++}
++
++static void tc_dma_destroy(void) {
++  free_irq(ETRAX_USB_RX_IRQ, NULL);
++  free_irq(ETRAX_USB_TX_IRQ, NULL);
++
++  cris_free_dma(USB_TX_DMA_NBR, "ETRAX 100LX built-in USB (Tx)");
++  cris_free_dma(USB_RX_DMA_NBR, "ETRAX 100LX built-in USB (Rx)");
++
++}
++
++static void tc_dma_link_intr_urb(struct urb *urb);
++
++/* Handle processing of Bulk, Ctrl and Intr queues */
++static void tc_dma_process_queue(int epid) {
++  struct urb *urb;
++  struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++  unsigned long flags;
++  char toggle;
++
++  if(epid_state[epid].disabled) {
++    /* Don't process any URBs on a disabled endpoint */
++    return;
++  }
++
++  /* Do not disturb us while fiddling with EPs and epids */
++  local_irq_save(flags);
++
++  /* For bulk, Ctrl and Intr can we only have one URB active at a time for
++     a specific EP. */
++  if(activeUrbList[epid] != NULL) {
++    /* An URB is already active on EP, skip checking queue */
++    local_irq_restore(flags);
++    return;
++  }
++
++  urb = urb_list_first(epid);
++  if(urb == NULL) {
++    /* No URB waiting in EP queue. Nothing do to */
++    local_irq_restore(flags);
++    return;
++  }
++
++  urb_priv = urb->hcpriv;
++  ASSERT(urb_priv != NULL);
++  ASSERT(urb_priv->urb_state == NOT_STARTED);
++  ASSERT(!usb_pipeisoc(urb->pipe));
++
++  /* Remove this URB from the queue and move it to active */
++  activeUrbList[epid] = urb;
++  urb_list_del(urb, epid);
++
++  urb_priv->urb_state = STARTED;
++
++  /* Reset error counters (regardless of which direction this traffic is). */
++  etrax_epid_clear_error(epid);
++
++  /* Special handling of Intr EP lists */
++  if(usb_pipeint(urb->pipe)) {
++    tc_dma_link_intr_urb(urb);
++    local_irq_restore(flags);
++    return;
++  }
++
++  /* Software must preset the toggle bits for Bulk and Ctrl */
++  if(usb_pipecontrol(urb->pipe)) {
++    /* Toggle bits are initialized only during setup transaction in a
++       CTRL transfer */
++    etrax_epid_set_toggle(epid, 0, 0);
++    etrax_epid_set_toggle(epid, 1, 0);
++  } else {
++    toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
++			   usb_pipeout(urb->pipe));
++    etrax_epid_set_toggle(epid, usb_pipeout(urb->pipe), toggle);
++  }
++
++  tc_dbg("Added SBs from (URB:0x%x %s %s) to epid %d: %s\n",
++	 (unsigned int)urb, str_dir(urb->pipe), str_type(urb->pipe), epid,
++	 sblist_to_str(urb_priv->first_sb));
++
++  /* We start the DMA sub channel without checking if it's running or not,
++     because:
++     1) If it's already running, issuing the start command is a nop.
++     2) We avoid a test-and-set race condition. */
++  switch(usb_pipetype(urb->pipe)) {
++  case PIPE_BULK:
++    /* Assert that the EP descriptor is disabled. */
++    ASSERT(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
++
++    /* Set up and enable the EP descriptor. */
++    TxBulkEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++    TxBulkEPList[epid].hw_len = 0;
++    TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++
++    /* Check if the dummy list is already with us (if several urbs were queued). */
++    if (usb_pipein(urb->pipe) && (TxBulkEPList[epid].next != virt_to_phys(&TxBulkDummyEPList[epid][0]))) {
++      tc_dbg("Inviting dummy list to the party for urb 0x%lx, epid %d", 
++	     (unsigned long)urb, epid);
++      
++      /* We don't need to check if the DMA is at this EP or not before changing the
++	 next pointer, since we will do it in one 32-bit write (EP descriptors are
++	 32-bit aligned). */
++      TxBulkEPList[epid].next = virt_to_phys(&TxBulkDummyEPList[epid][0]);
++    }
++
++    restart_dma8_sub0();
++
++    /* Update/restart the bulk start timer since we just started the channel.*/
++    mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
++    /* Update/restart the bulk eot timer since we just inserted traffic. */
++    mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
++    break;
++  case PIPE_CONTROL:
++    /* Assert that the EP descriptor is disabled. */
++    ASSERT(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
++
++    /* Set up and enable the EP descriptor. */
++    TxCtrlEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++    TxCtrlEPList[epid].hw_len = 0;
++    TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++
++    *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
++    break;
++  }
++  local_irq_restore(flags);
++}
++
++static void tc_dma_link_intr_urb(struct urb *urb) {
++  struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++  volatile struct USB_EP_Desc *tmp_ep;
++  struct USB_EP_Desc *ep_desc;
++  int i = 0, epid;
++  int pool_idx = 0;
++
++  ASSERT(urb_priv != NULL);
++  epid = urb_priv->epid;
++  ASSERT(urb_priv->interval > 0);
++  ASSERT(urb_priv->intr_ep_pool_length > 0);
++
++  tmp_ep = &TxIntrEPList[0];
++
++  /* Only insert one EP descriptor in list for Out Intr URBs.
++     We can only handle Out Intr with interval of 128ms because
++     it's not possible to insert several Out Intr EPs because they
++     are not consumed by the DMA. */
++  if(usb_pipeout(urb->pipe)) {
++    ep_desc = urb_priv->intr_ep_pool[0];
++    ASSERT(ep_desc);
++    ep_desc->next = tmp_ep->next;
++    tmp_ep->next = virt_to_phys(ep_desc);
++    i++;
++  } else {
++    /* Loop through Intr EP descriptor list and insert EP for URB at
++       specified interval */
++    do {
++      /* Each EP descriptor with eof flag sat signals a new frame */
++      if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) {
++	/* Insert a EP from URBs EP pool at correct interval */
++	if ((i % urb_priv->interval) == 0) {
++	  ep_desc = urb_priv->intr_ep_pool[pool_idx];
++	  ASSERT(ep_desc);
++	  ep_desc->next = tmp_ep->next;
++	  tmp_ep->next = virt_to_phys(ep_desc);
++	  pool_idx++;
++	  ASSERT(pool_idx <= urb_priv->intr_ep_pool_length);
++	}
++	i++;
++      }
++      tmp_ep = (struct USB_EP_Desc *)phys_to_virt(tmp_ep->next);
++    } while(tmp_ep != &TxIntrEPList[0]);
++  }
++
++  intr_dbg("Added SBs to intr epid %d: %s interval:%d (%d EP)\n", epid,
++	   sblist_to_str(urb_priv->first_sb), urb_priv->interval, pool_idx);
++
++  /* We start the DMA sub channel without checking if it's running or not,
++     because:
++     1) If it's already running, issuing the start command is a nop.
++     2) We avoid a test-and-set race condition. */
++  *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
++}
++
++  /* hinko ignore usb_pipeisoc */
++#if 0
++static void tc_dma_process_isoc_urb(struct urb *urb) {
++  unsigned long flags;
++  struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++  int epid;
++
++  /* Do not disturb us while fiddling with EPs and epids */
++  local_irq_save(flags);
++
++  ASSERT(urb_priv);
++  ASSERT(urb_priv->first_sb);
++  epid = urb_priv->epid;
++
++  if(activeUrbList[epid] == NULL) {
++    /* EP is idle, so make this URB active */
++    activeUrbList[epid] = urb;
++    urb_list_del(urb, epid);
++    ASSERT(TxIsocEPList[epid].sub == 0);
++    ASSERT(!(TxIsocEPList[epid].command &
++	     IO_STATE(USB_EP_command, enable, yes)));
++
++    /* Differentiate between In and Out Isoc. Because In SBs are not consumed*/
++    if(usb_pipein(urb->pipe)) {
++    /* Each EP for In Isoc will have only one SB descriptor, setup when
++       submitting the first active urb. We do it here by copying from URBs
++       pre-allocated SB. */
++      memcpy((void *)&(TxIsocSBList[epid]), urb_priv->first_sb,
++	     sizeof(TxIsocSBList[epid]));
++      TxIsocEPList[epid].hw_len = 0;
++      TxIsocEPList[epid].sub = virt_to_phys(&(TxIsocSBList[epid]));
++    } else {
++      /* For Out Isoc we attach the pre-allocated list of SBs for the URB */
++      TxIsocEPList[epid].hw_len = 0;
++      TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++
++      isoc_dbg("Attached first URB:0x%x[%d] to epid:%d first_sb:0x%x"
++	       " last_sb::0x%x\n",
++	       (unsigned int)urb, urb_priv->urb_num, epid,
++	       (unsigned int)(urb_priv->first_sb),
++	       (unsigned int)(urb_priv->last_sb));
++    }
++
++    if (urb->transfer_flags & URB_ISO_ASAP) {
++      /* The isoc transfer should be started as soon as possible. The
++	 start_frame field is a return value if URB_ISO_ASAP was set. Comparing
++	 R_USB_FM_NUMBER with a USB Chief trace shows that the first isoc IN
++	 token is sent 2 frames later. I'm not sure how this affects usage of
++	 the start_frame field by the device driver, or how it affects things
++	 when USB_ISO_ASAP is not set, so therefore there's no compensation for
++	 the 2 frame "lag" here. */
++      urb->start_frame = (*R_USB_FM_NUMBER & 0x7ff);
++      TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
++      urb_priv->urb_state = STARTED;
++      isoc_dbg("URB_ISO_ASAP set, urb->start_frame set to %d\n",
++	       urb->start_frame);
++    } else {
++      /* Not started yet. */
++      urb_priv->urb_state = NOT_STARTED;
++      isoc_warn("urb_priv->urb_state set to NOT_STARTED for URB:0x%x\n",
++		(unsigned int)urb);
++    }
++
++  } else {
++    /* An URB is already active on the EP. Leave URB in queue and let
++       finish_isoc_urb process it after current active URB */
++    ASSERT(TxIsocEPList[epid].sub != 0);
++
++    if(usb_pipein(urb->pipe)) {
++      /* Because there already is a active In URB on this epid we do nothing
++         and the finish_isoc_urb() function will handle switching to next URB*/
++
++    } else { /* For Out Isoc, insert new URBs traffic last in SB-list. */
++      struct USB_SB_Desc *temp_sb_desc;
++
++      /* Set state STARTED to all Out Isoc URBs added to SB list because we
++         don't know how many of them that are finished before descr interrupt*/
++      urb_priv->urb_state = STARTED;
++
++      /* Find end of current SB list by looking for SB with eol flag sat */
++      temp_sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
++      while ((temp_sb_desc->command & IO_MASK(USB_SB_command, eol)) !=
++	     IO_STATE(USB_SB_command, eol, yes)) {
++	ASSERT(temp_sb_desc->next);
++	temp_sb_desc = phys_to_virt(temp_sb_desc->next);
++      }
++
++      isoc_dbg("Appended URB:0x%x[%d] (first:0x%x last:0x%x) to epid:%d"
++	       " sub:0x%x eol:0x%x\n",
++	       (unsigned int)urb, urb_priv->urb_num,
++	       (unsigned int)(urb_priv->first_sb),
++	       (unsigned int)(urb_priv->last_sb), epid,
++	       (unsigned int)phys_to_virt(TxIsocEPList[epid].sub),
++	       (unsigned int)temp_sb_desc);
++
++      /* Next pointer must be set before eol is removed. */
++      temp_sb_desc->next = virt_to_phys(urb_priv->first_sb);
++      /* Clear the previous end of list flag since there is a new in the
++	 added SB descriptor list. */
++      temp_sb_desc->command &= ~IO_MASK(USB_SB_command, eol);
++
++      if (!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
++	__u32 epid_data;
++	/* 8.8.5 in Designer's Reference says we should check for and correct
++	   any errors in the EP here.  That should not be necessary if
++	   epid_attn is handled correctly, so we assume all is ok. */
++	epid_data = etrax_epid_iso_get(epid);
++	if (IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data) !=
++	    IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
++	  isoc_err("Disabled Isoc EP with error:%d on epid:%d when appending"
++		   " URB:0x%x[%d]\n",
++		   IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data), epid,
++		   (unsigned int)urb, urb_priv->urb_num);
++	}
++
++	/* The SB list was exhausted. */
++	if (virt_to_phys(urb_priv->last_sb) != TxIsocEPList[epid].sub) {
++	  /* The new sublist did not get processed before the EP was
++	     disabled.  Setup the EP again. */
++
++	  if(virt_to_phys(temp_sb_desc) == TxIsocEPList[epid].sub) {
++	    isoc_dbg("EP for epid:%d stoped at SB:0x%x before newly inserted"
++		     ", restarting from this URBs SB:0x%x\n",
++		     epid, (unsigned int)temp_sb_desc,
++		     (unsigned int)(urb_priv->first_sb));
++	    TxIsocEPList[epid].hw_len = 0;
++	    TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
++	    urb->start_frame = (*R_USB_FM_NUMBER & 0x7ff);
++	    /* Enable the EP again so data gets processed this time */
++	    TxIsocEPList[epid].command |=
++	      IO_STATE(USB_EP_command, enable, yes);
++
++	  } else {
++	    /* The EP has been disabled but not at end this URB (god knows
++	       where). This should generate an epid_attn so we should not be
++	       here */
++	    isoc_warn("EP was disabled on sb:0x%x before SB list for"
++		     " URB:0x%x[%d] got processed\n",
++		     (unsigned int)phys_to_virt(TxIsocEPList[epid].sub),
++		     (unsigned int)urb, urb_priv->urb_num);
++	  }
++	} else {
++	  /* This might happend if we are slow on this function and isn't
++	     an error. */
++	  isoc_dbg("EP was disabled and finished with SBs from appended"
++		   " URB:0x%x[%d]\n", (unsigned int)urb, urb_priv->urb_num);
++	}
++      }
++    }
++  }
++  
++  /* Start the DMA sub channel */
++  *R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
++
++  local_irq_restore(flags);
++}
++#endif
++
++static void tc_dma_unlink_intr_urb(struct urb *urb) {
++  struct crisv10_urb_priv *urb_priv = urb->hcpriv;
++  volatile struct USB_EP_Desc *first_ep;  /* First EP in the list. */
++  volatile struct USB_EP_Desc *curr_ep;   /* Current EP, the iterator. */
++  volatile struct USB_EP_Desc *next_ep;   /* The EP after current. */
++  volatile struct USB_EP_Desc *unlink_ep; /* The one we should remove from
++					     the list. */
++  int count = 0;
++  volatile int timeout = 10000;
++  int epid;
++
++  /* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the
++     List". */
++  ASSERT(urb_priv);
++  ASSERT(urb_priv->intr_ep_pool_length > 0);
++  epid = urb_priv->epid;
++
++  /* First disable all Intr EPs belonging to epid for this URB */
++  first_ep = &TxIntrEPList[0];
++  curr_ep = first_ep;
++  do {
++    next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++    if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
++      /* Disable EP */
++      next_ep->command &= ~IO_MASK(USB_EP_command, enable);
++    }
++    curr_ep = phys_to_virt(curr_ep->next);
++  } while (curr_ep != first_ep);
++
++
++  /* Now unlink all EPs belonging to this epid from Descr list */
++  first_ep = &TxIntrEPList[0];
++  curr_ep = first_ep;
++  do {
++    next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++    if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
++      /* This is the one we should unlink. */
++      unlink_ep = next_ep;
++
++      /* Actually unlink the EP from the DMA list. */
++      curr_ep->next = unlink_ep->next;
++
++      /* Wait until the DMA is no longer at this descriptor. */
++      while((*R_DMA_CH8_SUB2_EP == virt_to_phys(unlink_ep)) &&
++	    (timeout-- > 0));
++      if(timeout == 0) {
++	warn("Timeout while waiting for DMA-TX-Intr to leave unlink EP\n");
++      }
++      
++      count++;
++    }
++    curr_ep = phys_to_virt(curr_ep->next);
++  } while (curr_ep != first_ep);
++
++  if(count != urb_priv->intr_ep_pool_length) {
++    intr_warn("Unlinked %d of %d Intr EPs for URB:0x%x[%d]\n", count,
++	      urb_priv->intr_ep_pool_length, (unsigned int)urb,
++	      urb_priv->urb_num);
++  } else {
++    intr_dbg("Unlinked %d of %d interrupt EPs for URB:0x%x\n", count,
++	     urb_priv->intr_ep_pool_length, (unsigned int)urb);
++  }
++}
++
++static void check_finished_bulk_tx_epids(struct usb_hcd *hcd,
++						    int timer) {
++  unsigned long flags;
++  int epid;
++  struct urb *urb;
++  struct crisv10_urb_priv * urb_priv;
++  __u32 epid_data;
++
++  /* Protect TxEPList */
++  local_irq_save(flags);
++
++  for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++    /* A finished EP descriptor is disabled and has a valid sub pointer */
++    if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
++	(TxBulkEPList[epid].sub != 0)) {
++
++      /* Get the active URB for this epid */
++      urb = activeUrbList[epid];
++      /* Sanity checks */
++      ASSERT(urb);
++      urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++      ASSERT(urb_priv);
++      
++      /* Only handle finished out Bulk EPs here,
++	 and let RX interrupt take care of the rest */
++      if(!epid_out_traffic(epid)) {
++	continue;
++      }
++
++      if(timer) {
++	tc_warn("Found finished %s Bulk epid:%d URB:0x%x[%d] from timeout\n",
++		epid_out_traffic(epid) ? "Out" : "In", epid, (unsigned int)urb,
++		urb_priv->urb_num);
++      } else {
++	tc_dbg("Found finished %s Bulk epid:%d URB:0x%x[%d] from interrupt\n",
++	       epid_out_traffic(epid) ? "Out" : "In", epid, (unsigned int)urb,
++	       urb_priv->urb_num);
++      }
++
++      if(urb_priv->urb_state == UNLINK) {
++	/* This Bulk URB is requested to be unlinked, that means that the EP
++	   has been disabled and we might not have sent all data */
++	tc_finish_urb(hcd, urb, urb->status);
++	continue;
++      }
++
++      ASSERT(urb_priv->urb_state == STARTED);
++      if (phys_to_virt(TxBulkEPList[epid].sub) != urb_priv->last_sb) {
++	tc_err("Endpoint got disabled before reaching last sb\n");
++      }
++	
++      epid_data = etrax_epid_get(epid);
++      if (IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data) ==
++	  IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
++	/* This means that the endpoint has no error, is disabled
++	   and had inserted traffic, i.e. transfer successfully completed. */
++	tc_finish_urb(hcd, urb, 0);
++      } else {
++	/* Shouldn't happen. We expect errors to be caught by epid
++	   attention. */
++	tc_err("Found disabled bulk EP desc (epid:%d error:%d)\n",
++	       epid, IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data));
++      }
++    } else {
++      tc_dbg("Ignoring In Bulk epid:%d, let RX interrupt handle it\n", epid);
++    }
++  }
++
++  local_irq_restore(flags);
++}
++
++static void check_finished_ctrl_tx_epids(struct usb_hcd *hcd) {
++  unsigned long flags;
++  int epid;
++  struct urb *urb;
++  struct crisv10_urb_priv * urb_priv;
++  __u32 epid_data;
++
++  /* Protect TxEPList */
++  local_irq_save(flags);
++
++  for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++    if(epid == DUMMY_EPID)
++      continue;
++
++    /* A finished EP descriptor is disabled and has a valid sub pointer */
++    if (!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
++	(TxCtrlEPList[epid].sub != 0)) {
++      
++      /* Get the active URB for this epid */
++      urb = activeUrbList[epid];
++
++      if(urb == NULL) {
++	tc_warn("Found finished Ctrl epid:%d with no active URB\n", epid);
++	continue;
++      }
++      
++      /* Sanity checks */
++      ASSERT(usb_pipein(urb->pipe));
++      urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++      ASSERT(urb_priv);
++      if (phys_to_virt(TxCtrlEPList[epid].sub) != urb_priv->last_sb) {
++	tc_err("Endpoint got disabled before reaching last sb\n");
++      }
++
++      epid_data = etrax_epid_get(epid);
++      if (IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data) ==
++	  IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
++	/* This means that the endpoint has no error, is disabled
++	   and had inserted traffic, i.e. transfer successfully completed. */
++
++	/* Check if RX-interrupt for In Ctrl has been processed before
++	   finishing the URB */
++	if(urb_priv->ctrl_rx_done) {
++	  tc_dbg("Finishing In Ctrl URB:0x%x[%d] in tx_interrupt\n",
++		 (unsigned int)urb, urb_priv->urb_num);
++	  tc_finish_urb(hcd, urb, 0);
++	} else {
++	  /* If we get zout descriptor interrupt before RX was done for a
++	     In Ctrl transfer, then we flag that and it will be finished
++	     in the RX-Interrupt */
++	  urb_priv->ctrl_zout_done = 1;
++	  tc_dbg("Got zout descr interrupt before RX interrupt\n");
++	}
++      } else {
++	/* Shouldn't happen. We expect errors to be caught by epid
++	   attention. */
++	tc_err("Found disabled Ctrl EP desc (epid:%d URB:0x%x[%d]) error_code:%d\n", epid, (unsigned int)urb, urb_priv->urb_num, IO_EXTRACT(R_USB_EPT_DATA, error_code, epid_data));
++	__dump_ep_desc(&(TxCtrlEPList[epid]));
++	__dump_ept_data(epid);
++      }      
++    }
++  }
++  local_irq_restore(flags);
++}
++
++  /* hinko ignore usb_pipeisoc */
++#if 0
++/* This function goes through all epids that are setup for Out Isoc transfers
++   and marks (isoc_out_done) all queued URBs that the DMA has finished
++   transfer for.
++   No URB completetion is done here to make interrupt routine return quickly.
++   URBs are completed later with help of complete_isoc_bottom_half() that
++   becomes schedules when this functions is finished. */
++static void check_finished_isoc_tx_epids(void) {
++  unsigned long flags;
++  int epid;
++  struct urb *urb;
++  struct crisv10_urb_priv * urb_priv;
++  struct USB_SB_Desc* sb_desc;
++  int epid_done;
++
++  /* Protect TxIsocEPList */
++  local_irq_save(flags);
++
++  for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++    if (TxIsocEPList[epid].sub == 0 || epid == INVALID_EPID ||
++	!epid_out_traffic(epid)) {
++      /* Nothing here to see. */
++      continue;
++    }
++    ASSERT(epid_inuse(epid));
++    ASSERT(epid_isoc(epid));
++
++    sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
++    /* Find the last descriptor of the currently active URB for this ep.
++       This is the first descriptor in the sub list marked for a descriptor
++       interrupt. */
++    while (sb_desc && !IO_EXTRACT(USB_SB_command, intr, sb_desc->command)) {
++      sb_desc = sb_desc->next ? phys_to_virt(sb_desc->next) : 0;
++    }
++    ASSERT(sb_desc);
++
++    isoc_dbg("Descr IRQ checking epid:%d sub:0x%x intr:0x%x\n",
++	     epid, (unsigned int)phys_to_virt(TxIsocEPList[epid].sub),
++	     (unsigned int)sb_desc);
++
++    urb = activeUrbList[epid];
++    if(urb == NULL) {
++      isoc_err("Isoc Descr irq on epid:%d with no active URB\n", epid);
++      continue;
++    }
++
++    epid_done = 0;
++    while(urb && !epid_done) {
++      /* Sanity check. */
++      ASSERT(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
++      ASSERT(usb_pipeout(urb->pipe));
++      
++      urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++      ASSERT(urb_priv);
++      ASSERT(urb_priv->urb_state == STARTED ||
++	     urb_priv->urb_state == UNLINK);
++      
++      if (sb_desc != urb_priv->last_sb) {
++	/* This urb has been sent. */
++	urb_priv->isoc_out_done = 1;
++
++      } else { /* Found URB that has last_sb as the interrupt reason */
++
++	/* Check if EP has been disabled, meaning that all transfers are done*/
++	if(!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
++	  ASSERT((sb_desc->command & IO_MASK(USB_SB_command, eol)) ==
++		 IO_STATE(USB_SB_command, eol, yes));
++	  ASSERT(sb_desc->next == 0);
++	  urb_priv->isoc_out_done = 1;
++	} else {
++	  isoc_dbg("Skipping URB:0x%x[%d] because EP not disabled yet\n",
++		   (unsigned int)urb, urb_priv->urb_num);
++	}
++	/* Stop looking any further in queue */
++	epid_done = 1;	
++      }
++
++      if (!epid_done) {
++	if(urb == activeUrbList[epid]) {
++	  urb = urb_list_first(epid);
++	} else {
++	  urb = urb_list_next(urb, epid);
++	}
++      }
++    } /* END: while(urb && !epid_done) */
++  }
++
++  local_irq_restore(flags);
++}
++
++
++/* This is where the Out Isoc URBs are realy completed. This function is
++   scheduled from tc_dma_tx_interrupt() when one or more Out Isoc transfers
++   are done. This functions completes all URBs earlier marked with
++   isoc_out_done by fast interrupt routine check_finished_isoc_tx_epids() */
++
++static void complete_isoc_bottom_half(void *data) {
++  struct crisv10_isoc_complete_data *comp_data;
++  struct usb_iso_packet_descriptor *packet;
++  struct crisv10_urb_priv * urb_priv;
++  unsigned long flags;
++  struct urb* urb;
++  int epid_done;
++  int epid;
++  int i;
++
++  comp_data = (struct crisv10_isoc_complete_data*)data;
++
++  local_irq_save(flags);
++
++  for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
++    if(!epid_inuse(epid) || !epid_isoc(epid) || !epid_out_traffic(epid) || epid == DUMMY_EPID) {
++      /* Only check valid Out Isoc epids */
++      continue;
++    }
++
++    isoc_dbg("Isoc bottom-half checking epid:%d, sub:0x%x\n", epid,
++	     (unsigned int)phys_to_virt(TxIsocEPList[epid].sub));
++
++    /* The descriptor interrupt handler has marked all transmitted Out Isoc
++       URBs with isoc_out_done.  Now we traverse all epids and for all that
++       have out Isoc traffic we traverse its URB list and complete the
++       transmitted URBs. */
++    epid_done = 0;
++    while (!epid_done) {
++
++      /* Get the active urb (if any) */
++      urb = activeUrbList[epid];
++      if (urb == 0) {
++	isoc_dbg("No active URB on epid:%d anymore\n", epid);
++	epid_done = 1;
++	continue;
++      }
++
++      /* Sanity check. */
++      ASSERT(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
++      ASSERT(usb_pipeout(urb->pipe));
++
++      urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++      ASSERT(urb_priv);
++
++      if (!(urb_priv->isoc_out_done)) {
++	/* We have reached URB that isn't flaged done yet, stop traversing. */
++	isoc_dbg("Stoped traversing Out Isoc URBs on epid:%d"
++		 " before not yet flaged URB:0x%x[%d]\n",
++		 epid, (unsigned int)urb, urb_priv->urb_num);
++	epid_done = 1;
++	continue;
++      }
++
++      /* This urb has been sent. */
++      isoc_dbg("Found URB:0x%x[%d] that is flaged isoc_out_done\n",
++	       (unsigned int)urb, urb_priv->urb_num);
++
++      /* Set ok on transfered packets for this URB and finish it */
++      for (i = 0; i < urb->number_of_packets; i++) {
++	packet = &urb->iso_frame_desc[i];
++	packet->status = 0;
++	packet->actual_length = packet->length;
++      }
++      urb_priv->isoc_packet_counter = urb->number_of_packets;
++      tc_finish_urb(comp_data->hcd, urb, 0);
++
++    } /* END: while(!epid_done) */
++  } /* END: for(epid...) */
++
++  local_irq_restore(flags);
++  kmem_cache_free(isoc_compl_cache, comp_data);
++}
++#endif
++
++static void check_finished_intr_tx_epids(struct usb_hcd *hcd) {
++  unsigned long flags;
++  int epid;
++  struct urb *urb;
++  struct crisv10_urb_priv * urb_priv;
++  volatile struct USB_EP_Desc *curr_ep;   /* Current EP, the iterator. */
++  volatile struct USB_EP_Desc *next_ep;   /* The EP after current. */
++
++  /* Protect TxintrEPList */
++  local_irq_save(flags);
++
++  for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++    if(!epid_inuse(epid) || !epid_intr(epid) || !epid_out_traffic(epid)) {
++      /* Nothing to see on this epid. Only check valid Out Intr epids */
++      continue;
++    }
++
++    urb = activeUrbList[epid];
++    if(urb == 0) {
++      intr_warn("Found Out Intr epid:%d with no active URB\n", epid);
++      continue;
++    }
++
++    /* Sanity check. */
++    ASSERT(usb_pipetype(urb->pipe) == PIPE_INTERRUPT);
++    ASSERT(usb_pipeout(urb->pipe));
++    
++    urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++    ASSERT(urb_priv);
++
++    /* Go through EPs between first and second sof-EP. It's here Out Intr EPs
++       are inserted.*/
++    curr_ep = &TxIntrEPList[0];
++    do {
++      next_ep = (struct USB_EP_Desc *)phys_to_virt(curr_ep->next);
++      if(next_ep == urb_priv->intr_ep_pool[0]) {
++	/* We found the Out Intr EP for this epid */
++	
++	/* Disable it so it doesn't get processed again */
++	next_ep->command &= ~IO_MASK(USB_EP_command, enable);
++
++	/* Finish the active Out Intr URB with status OK */
++	tc_finish_urb(hcd, urb, 0);
++      }
++      curr_ep = phys_to_virt(curr_ep->next);
++    } while (curr_ep != &TxIntrEPList[1]);
++
++  }
++  local_irq_restore(flags);
++}
++
++/* Interrupt handler for DMA8/IRQ24 with subchannels (called from hardware intr) */
++static irqreturn_t tc_dma_tx_interrupt(int irq, void *vhc) {
++  struct usb_hcd *hcd = (struct usb_hcd*)vhc;
++  ASSERT(hcd);
++
++  if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) {
++    /* Clear this interrupt */
++    *R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do);
++    restart_dma8_sub0();
++  }
++
++  if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) {
++    /* Clear this interrupt */
++    *R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do);
++    check_finished_ctrl_tx_epids(hcd);
++  }
++
++  if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) {
++    /* Clear this interrupt */
++    *R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do);
++    check_finished_intr_tx_epids(hcd);
++  }
++
++  /* hinko ignore usb_pipeisoc */
++#if 0
++  if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) {
++    struct crisv10_isoc_complete_data* comp_data;
++
++    /* Flag done Out Isoc for later completion */
++    check_finished_isoc_tx_epids();
++
++    /* Clear this interrupt */
++    *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do);
++    /* Schedule bottom half of Out Isoc completion function. This function
++       finishes the URBs marked with isoc_out_done */
++    comp_data = (struct crisv10_isoc_complete_data*)
++      kmem_cache_alloc(isoc_compl_cache, GFP_ATOMIC);
++    ASSERT(comp_data != NULL);
++    comp_data ->hcd = hcd;
++
++    //INIT_WORK(&comp_data->usb_bh, complete_isoc_bottom_half, comp_data);
++    INIT_WORK(&comp_data->usb_bh, complete_isoc_bottom_half);
++    schedule_work(&comp_data->usb_bh);
++  }
++#endif
++
++  return IRQ_HANDLED;
++}
++
++/* Interrupt handler for DMA9/IRQ25 (called from hardware intr) */
++static irqreturn_t tc_dma_rx_interrupt(int irq, void *vhc) {
++  unsigned long flags;
++  struct urb *urb;
++  struct usb_hcd *hcd = (struct usb_hcd*)vhc;
++  struct crisv10_urb_priv *urb_priv;
++  int epid = 0;
++  int real_error;
++
++  ASSERT(hcd);
++
++  /* Clear this interrupt. */
++  *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
++
++  /* Custom clear interrupt for this interrupt */
++  /* The reason we cli here is that we call the driver's callback functions. */
++  local_irq_save(flags);
++
++  /* Note that this while loop assumes that all packets span only
++     one rx descriptor. */
++  while(myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) {
++    epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status);
++    /* Get the active URB for this epid */
++    urb = activeUrbList[epid];
++
++    ASSERT(epid_inuse(epid));
++    if (!urb) {
++      dma_err("No urb for epid %d in rx interrupt\n", epid);
++      goto skip_out;
++    }
++
++    /* Check if any errors on epid */
++    real_error = 0;
++    if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {
++      __u32 r_usb_ept_data;
++
++      if (usb_pipeisoc(urb->pipe)) {
++	r_usb_ept_data = etrax_epid_iso_get(epid);
++	if((r_usb_ept_data & IO_MASK(R_USB_EPT_DATA_ISO, valid)) &&
++	   (IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data) == 0) &&
++	   (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata))) {
++	  /* Not an error, just a failure to receive an expected iso
++	     in packet in this frame.  This is not documented
++	     in the designers reference. Continue processing.
++	  */
++	} else real_error = 1;
++      } else real_error = 1;
++    }
++
++    if(real_error) {
++      dma_err("Error in RX descr on epid:%d for URB 0x%x",
++	      epid, (unsigned int)urb);
++      dump_ept_data(epid);
++      dump_in_desc(myNextRxDesc);
++      goto skip_out;
++    }
++
++    urb_priv = (struct crisv10_urb_priv *)urb->hcpriv;
++    ASSERT(urb_priv);
++    ASSERT(urb_priv->urb_state == STARTED ||
++	   urb_priv->urb_state == UNLINK);
++
++    if ((usb_pipetype(urb->pipe) == PIPE_BULK) ||
++	(usb_pipetype(urb->pipe) == PIPE_CONTROL) ||
++	(usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
++
++      /* We get nodata for empty data transactions, and the rx descriptor's
++	 hw_len field is not valid in that case. No data to copy in other
++	 words. */
++      if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
++	/* No data to copy */
++      } else {
++	/*
++	dma_dbg("Processing RX for URB:0x%x epid:%d (data:%d ofs:%d)\n",
++		(unsigned int)urb, epid, myNextRxDesc->hw_len,
++		urb_priv->rx_offset);
++	*/
++	/* Only copy data if URB isn't flaged to be unlinked*/
++	if(urb_priv->urb_state != UNLINK) {
++	  /* Make sure the data fits in the buffer. */
++	  if(urb_priv->rx_offset + myNextRxDesc->hw_len
++	     <= urb->transfer_buffer_length) {
++
++	    /* Copy the data to URBs buffer */
++	    memcpy(urb->transfer_buffer + urb_priv->rx_offset,
++		   phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);
++	    urb_priv->rx_offset += myNextRxDesc->hw_len;
++	  } else {
++	    /* Signal overflow when returning URB */
++	    urb->status = -EOVERFLOW;
++	    tc_finish_urb_later(hcd, urb, urb->status);
++	  }
++	}
++      }
++
++      /* Check if it was the last packet in the transfer */
++      if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {
++	/* Special handling for In Ctrl URBs. */
++	if(usb_pipecontrol(urb->pipe) && usb_pipein(urb->pipe) &&
++	   !(urb_priv->ctrl_zout_done)) {
++	  /* Flag that RX part of Ctrl transfer is done. Because zout descr
++	     interrupt hasn't happend yet will the URB be finished in the
++	     TX-Interrupt. */
++	  urb_priv->ctrl_rx_done = 1;
++	  tc_dbg("Not finishing In Ctrl URB:0x%x from rx_interrupt, waiting"
++		 " for zout\n", (unsigned int)urb);
++	} else {
++	  tc_finish_urb(hcd, urb, 0);
++	}
++      }
++    } else { /* ISOC RX */
++      /*
++      isoc_dbg("Processing RX for epid:%d (URB:0x%x) ISOC pipe\n",
++	       epid, (unsigned int)urb);
++      */
++
++      struct usb_iso_packet_descriptor *packet;
++
++      if (urb_priv->urb_state == UNLINK) {
++	isoc_warn("Ignoring Isoc Rx data for urb being unlinked.\n");
++	goto skip_out;
++      } else if (urb_priv->urb_state == NOT_STARTED) {
++	isoc_err("What? Got Rx data for Isoc urb that isn't started?\n");
++	goto skip_out;
++      }
++
++      packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter];
++      ASSERT(packet);
++      packet->status = 0;
++
++      if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
++	/* We get nodata for empty data transactions, and the rx descriptor's
++	   hw_len field is not valid in that case. We copy 0 bytes however to
++	   stay in synch. */
++	packet->actual_length = 0;
++      } else {
++	packet->actual_length = myNextRxDesc->hw_len;
++	/* Make sure the data fits in the buffer. */
++	ASSERT(packet->actual_length <= packet->length);
++	memcpy(urb->transfer_buffer + packet->offset,
++	       phys_to_virt(myNextRxDesc->buf), packet->actual_length);
++	if(packet->actual_length > 0)
++	  isoc_dbg("Copied %d bytes, packet %d for URB:0x%x[%d]\n",
++		   packet->actual_length, urb_priv->isoc_packet_counter,
++		   (unsigned int)urb, urb_priv->urb_num);
++      }
++
++      /* Increment the packet counter. */
++      urb_priv->isoc_packet_counter++;
++
++      /* Note that we don't care about the eot field in the rx descriptor's
++	 status. It will always be set for isoc traffic. */
++      if (urb->number_of_packets == urb_priv->isoc_packet_counter) {
++	/* Complete the urb with status OK. */
++	tc_finish_urb(hcd, urb, 0);
++      }
++    }
++
++  skip_out:
++    myNextRxDesc->status = 0;
++    myNextRxDesc->command |= IO_MASK(USB_IN_command, eol);
++    myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);
++    myLastRxDesc = myNextRxDesc;
++    myNextRxDesc = phys_to_virt(myNextRxDesc->next);
++    flush_etrax_cache();
++    *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, restart);
++  }
++
++  local_irq_restore(flags);
++
++  return IRQ_HANDLED;
++}
++
++static void tc_bulk_start_timer_func(unsigned long dummy) {
++  /* We might enable an EP descriptor behind the current DMA position when
++     it's about to decide that there are no more bulk traffic and it should
++     stop the bulk channel.
++     Therefore we periodically check if the bulk channel is stopped and there
++     is an enabled bulk EP descriptor, in which case we start the bulk
++     channel. */
++  
++  if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
++    int epid;
++
++    timer_dbg("bulk_start_timer: Bulk DMA channel not running.\n");
++
++    for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
++      if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
++	timer_warn("Found enabled EP for epid %d, starting bulk channel.\n",
++		   epid);
++	restart_dma8_sub0();
++
++	/* Restart the bulk eot timer since we just started the bulk channel.*/
++	mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
++
++	/* No need to search any further. */
++	break;
++      }
++    }
++  } else {
++    timer_dbg("bulk_start_timer: Bulk DMA channel running.\n");
++  }
++}
++
++static void tc_bulk_eot_timer_func(unsigned long dummy) {
++  struct usb_hcd *hcd = (struct usb_hcd*)dummy;
++  ASSERT(hcd);
++  /* Because of a race condition in the top half, we might miss a bulk eot.
++     This timer "simulates" a bulk eot if we don't get one for a while,
++     hopefully correcting the situation. */
++  timer_dbg("bulk_eot_timer timed out.\n");
++  check_finished_bulk_tx_epids(hcd, 1);
++}
++
++
++/*************************************************************/
++/*************************************************************/
++/* Device driver block                                       */
++/*************************************************************/
++/*************************************************************/
++
++/* Forward declarations for device driver functions */
++static int devdrv_hcd_probe(struct device *);
++static int devdrv_hcd_remove(struct device *);
++#ifdef CONFIG_PM
++static int devdrv_hcd_suspend(struct device *, u32, u32);
++static int devdrv_hcd_resume(struct device *, u32);
++#endif /* CONFIG_PM */
++
++/* the device */
++static struct platform_device *devdrv_hc_platform_device;
++
++/* device driver interface */
++static struct device_driver devdrv_hc_device_driver = {
++  .name =			(char *) hc_name,
++  .bus =			&platform_bus_type,
++
++  .probe =		devdrv_hcd_probe,
++  .remove =		devdrv_hcd_remove,
++
++#ifdef CONFIG_PM
++  .suspend =		devdrv_hcd_suspend,
++  .resume =		devdrv_hcd_resume,
++#endif /* CONFIG_PM */
++};
++
++/* initialize the host controller and driver  */
++static int __init_or_module devdrv_hcd_probe(struct device *dev)
++{
++  struct usb_hcd *hcd;
++  struct crisv10_hcd *crisv10_hcd;
++  int retval;
++  int rev_maj, rev_min;
++
++  /* Check DMA burst length */
++  if(IO_EXTRACT(R_BUS_CONFIG, dma_burst, *R_BUS_CONFIG) !=
++     IO_STATE(R_BUS_CONFIG, dma_burst, burst32)) {
++    devdrv_err("Invalid DMA burst length in Etrax 100LX,"
++	       " needs to be 32\n");
++    return -EPERM;
++  }
++
++  hcd = usb_create_hcd(&crisv10_hc_driver, dev, dev_name(dev));
++  if (!hcd)
++    return -ENOMEM;
++
++  crisv10_hcd = hcd_to_crisv10_hcd(hcd);
++  spin_lock_init(&crisv10_hcd->lock);
++  crisv10_hcd->num_ports = num_ports();
++  crisv10_hcd->running = 0;
++
++  dev_set_drvdata(dev, crisv10_hcd);
++
++  devdrv_dbg("ETRAX USB IRQs HC:%d  RX:%d  TX:%d\n", ETRAX_USB_HC_IRQ,
++	  ETRAX_USB_RX_IRQ, ETRAX_USB_TX_IRQ);
++
++  /* Print out chip version read from registers */
++  rev_maj = *R_USB_REVISION & IO_MASK(R_USB_REVISION, major);
++  rev_min = *R_USB_REVISION & IO_MASK(R_USB_REVISION, minor);
++  if(rev_min == 0) {
++    devdrv_info("Etrax 100LX USB Revision %d v1,2\n", rev_maj);
++  } else {
++    devdrv_info("Etrax 100LX USB Revision %d v%d\n", rev_maj, rev_min);
++  }
++
++  devdrv_info("Bulk timer interval, start:%d eot:%d\n",
++	      BULK_START_TIMER_INTERVAL,
++	      BULK_EOT_TIMER_INTERVAL);
++
++
++  /* Init root hub data structures */
++  if(rh_init()) {
++    devdrv_err("Failed init data for Root Hub\n");
++    retval = -ENOMEM;
++  }
++
++  if(port_in_use(0)) {
++    if (cris_request_io_interface(if_usb_1, "ETRAX100LX USB-HCD")) {
++      printk(KERN_CRIT "usb-host: request IO interface usb1 failed");
++      retval = -EBUSY;
++      goto out;
++    }
++    devdrv_info("Claimed interface for USB physical port 1\n");
++  }
++  if(port_in_use(1)) {
++    if (cris_request_io_interface(if_usb_2, "ETRAX100LX USB-HCD")) {
++      /* Free first interface if second failed to be claimed */
++      if(port_in_use(0)) {
++	cris_free_io_interface(if_usb_1);
++      }
++      printk(KERN_CRIT "usb-host: request IO interface usb2 failed");
++      retval = -EBUSY;
++      goto out;
++    }
++    devdrv_info("Claimed interface for USB physical port 2\n");
++  }
++  
++  /* Init transfer controller structs and locks */
++  if((retval = tc_init(hcd)) != 0) {
++    goto out;
++  }
++
++  /* Attach interrupt functions for DMA and init DMA controller */
++  if((retval = tc_dma_init(hcd)) != 0) {
++    goto out;
++  }
++
++  /* Attach the top IRQ handler for USB controller interrupts */
++  if (request_irq(ETRAX_USB_HC_IRQ, crisv10_hcd_top_irq, 0,
++		  "ETRAX 100LX built-in USB (HC)", hcd)) {
++    err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ);
++    retval = -EBUSY;
++    goto out;
++  }
++
++  /* iso_eof is only enabled when isoc traffic is running. */
++  *R_USB_IRQ_MASK_SET =
++    /* IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set) | */
++    IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) |
++    IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) |
++    IO_STATE(R_USB_IRQ_MASK_SET, port_status, set) |
++    IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set);
++
++
++  crisv10_ready_wait();
++  /* Reset the USB interface. */
++  *R_USB_COMMAND =
++    IO_STATE(R_USB_COMMAND, port_sel, nop) |
++    IO_STATE(R_USB_COMMAND, port_cmd, reset) |
++    IO_STATE(R_USB_COMMAND, ctrl_cmd, reset);
++
++  /* Designer's Reference, p. 8 - 10 says we should Initate R_USB_FM_PSTART to
++     0x2A30 (10800), to guarantee that control traffic gets 10% of the
++     bandwidth, and periodic transfer may allocate the rest (90%).
++     This doesn't work though.
++     The value 11960 is chosen to be just after the SOF token, with a couple
++     of bit times extra for possible bit stuffing. */
++  *R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 11960);
++
++  crisv10_ready_wait();
++  /* Configure the USB interface as a host controller. */
++  *R_USB_COMMAND =
++    IO_STATE(R_USB_COMMAND, port_sel, nop) |
++    IO_STATE(R_USB_COMMAND, port_cmd, reset) |
++    IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config);
++
++
++  /* Check so controller not busy before enabling ports */
++  crisv10_ready_wait();
++
++  /* Enable selected USB ports */
++  if(port_in_use(0)) {
++    *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
++  } else {
++    *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
++  }
++  if(port_in_use(1)) {
++    *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
++  } else {
++    *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes);
++  }
++
++  crisv10_ready_wait();
++  /* Start processing of USB traffic. */
++  *R_USB_COMMAND =
++    IO_STATE(R_USB_COMMAND, port_sel, nop) |
++    IO_STATE(R_USB_COMMAND, port_cmd, reset) |
++    IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
++
++  /* Do not continue probing initialization before USB interface is done */
++  crisv10_ready_wait();
++
++  /* Register our Host Controller to USB Core
++   * Finish the remaining parts of generic HCD initialization: allocate the
++   * buffers of consistent memory, register the bus
++   * and call the driver's reset() and start() routines. */
++  retval = usb_add_hcd(hcd, ETRAX_USB_HC_IRQ, IRQF_DISABLED);
++  if (retval != 0) {
++    devdrv_err("Failed registering HCD driver\n");
++    goto out;
++  }
++
++  return 0;
++
++ out:
++  devdrv_hcd_remove(dev);
++  return retval;
++}
++
++
++/* cleanup after the host controller and driver */
++static int __init_or_module devdrv_hcd_remove(struct device *dev)
++{
++  struct crisv10_hcd *crisv10_hcd = dev_get_drvdata(dev);
++  struct usb_hcd *hcd;
++
++  if (!crisv10_hcd)
++    return 0;
++  hcd = crisv10_hcd_to_hcd(crisv10_hcd);
++
++
++  /* Stop USB Controller in Etrax 100LX */
++  crisv10_hcd_reset(hcd);
++
++  usb_remove_hcd(hcd);
++  devdrv_dbg("Removed HCD from USB Core\n");
++
++  /* Free USB Controller IRQ */
++  free_irq(ETRAX_USB_HC_IRQ, NULL);
++
++  /* Free resources */
++  tc_dma_destroy();
++  tc_destroy();
++
++
++  if(port_in_use(0)) {
++    cris_free_io_interface(if_usb_1);
++  }
++  if(port_in_use(1)) {
++    cris_free_io_interface(if_usb_2);
++  }
++
++  devdrv_dbg("Freed all claimed resources\n");
++
++  return 0;
++}
++
++
++#ifdef	CONFIG_PM
++
++static int devdrv_hcd_suspend(struct usb_hcd *hcd, u32 state, u32 level)
++{
++  return 0; /* no-op for now */
++}
++
++static int devdrv_hcd_resume(struct usb_hcd *hcd, u32 level)
++{
++  return 0; /* no-op for now */
++}
++
++#endif /* CONFIG_PM */
++
++
++
++/*************************************************************/
++/*************************************************************/
++/* Module block                                              */
++/*************************************************************/
++/*************************************************************/
++ 
++/* register driver */
++static int __init module_hcd_init(void) 
++{
++  
++  if (usb_disabled())
++    return -ENODEV;
++
++  /* Here we select enabled ports by following defines created from
++     menuconfig */
++#ifndef CONFIG_ETRAX_USB_HOST_PORT1
++  ports &= ~(1<<0);
++#endif
++#ifndef CONFIG_ETRAX_USB_HOST_PORT2
++  ports &= ~(1<<1);
++#endif
++
++  printk(KERN_INFO "%s version "VERSION" "COPYRIGHT"\n", product_desc);
++
++  devdrv_hc_platform_device =
++    platform_device_register_simple((char *) hc_name, 0, NULL, 0);
++
++  if (IS_ERR(devdrv_hc_platform_device))
++    return PTR_ERR(devdrv_hc_platform_device);
++  return driver_register(&devdrv_hc_device_driver);
++  /* 
++   * Note that we do not set the DMA mask for the device,
++   * i.e. we pretend that we will use PIO, since no specific
++   * allocation routines are needed for DMA buffers. This will
++   * cause the HCD buffer allocation routines to fall back to
++   * kmalloc().
++   */
++}
++
++/* unregister driver */
++static void __exit module_hcd_exit(void) 
++{	
++  driver_unregister(&devdrv_hc_device_driver);
++}
++
++
++/* Module hooks */
++module_init(module_hcd_init);
++module_exit(module_hcd_exit);
+diff -Nur linux-2.6.36.orig/drivers/usb/host/hc-crisv10.h linux-2.6.36/drivers/usb/host/hc-crisv10.h
+--- linux-2.6.36.orig/drivers/usb/host/hc-crisv10.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.36/drivers/usb/host/hc-crisv10.h	2010-11-15 17:57:18.000000000 +0100
+@@ -0,0 +1,331 @@
++#ifndef __LINUX_ETRAX_USB_H
++#define __LINUX_ETRAX_USB_H
++
++#include <linux/types.h>
++#include <linux/list.h>
++
++struct USB_IN_Desc {
++  volatile __u16 sw_len;
++  volatile __u16 command;
++  volatile unsigned long next;
++  volatile unsigned long buf;
++  volatile __u16 hw_len;
++  volatile __u16 status;
++};
++
++struct USB_SB_Desc {
++  volatile __u16 sw_len;
++  volatile __u16 command;
++  volatile unsigned long next;
++  volatile unsigned long buf;
++};
++
++struct USB_EP_Desc {
++  volatile __u16 hw_len;
++  volatile __u16 command;
++  volatile unsigned long sub;
++  volatile unsigned long next;
++};
++
++
++/* Root Hub port status struct */
++struct crisv10_rh {
++  volatile __u16 wPortChange[2];
++  volatile __u16 wPortStatusPrev[2];
++};
++
++/* HCD description */
++struct crisv10_hcd {
++  spinlock_t		lock;
++  __u8			num_ports;
++  __u8                  running;
++};
++
++
++/* Endpoint HC private data description */
++struct crisv10_ep_priv {
++  int epid;
++};
++
++/* Additional software state info for a USB Controller epid */
++struct etrax_epid {
++  __u8 inuse;       /* !0 = setup in Etrax and used for a endpoint */
++  __u8 disabled;    /* !0 = Temporarly disabled to avoid resubmission */
++  __u8 type;        /* Setup as: PIPE_BULK, PIPE_CONTROL ... */
++  __u8 out_traffic; /* !0 = This epid is for out traffic */
++};
++
++/* Struct to hold information of scheduled later URB completion */
++struct urb_later_data {
++//  struct work_struct ws;
++  struct delayed_work ws;
++  struct usb_hcd *hcd;
++  struct urb *urb;
++  int urb_num;
++  int status;
++};
++
++
++typedef enum {
++  STARTED,
++  NOT_STARTED,
++  UNLINK,
++} crisv10_urb_state_t;
++
++
++struct crisv10_urb_priv {
++  /* Sequence number for this URB. Every new submited URB gets this from
++     a incrementing counter. Used when a URB is scheduled for later finish to
++     be sure that the intended URB hasn't already been completed (device
++     drivers has a tendency to reuse URBs once they are completed, causing us
++     to not be able to single old ones out only based on the URB pointer.) */
++  __u32 urb_num;
++
++  /* The first_sb field is used for freeing all SB descriptors belonging
++     to an urb. The corresponding ep descriptor's sub pointer cannot be
++     used for this since the DMA advances the sub pointer as it processes
++     the sb list. */
++  struct USB_SB_Desc *first_sb;
++
++  /* The last_sb field referes to the last SB descriptor that belongs to
++     this urb. This is important to know so we can free the SB descriptors
++     that ranges between first_sb and last_sb. */
++  struct USB_SB_Desc *last_sb;
++  
++  /* The rx_offset field is used in ctrl and bulk traffic to keep track
++     of the offset in the urb's transfer_buffer where incoming data should be
++     copied to. */
++  __u32 rx_offset;
++  
++  /* Counter used in isochronous transfers to keep track of the
++     number of packets received/transmitted.  */
++  __u32 isoc_packet_counter;
++
++  /* Flag that marks if this Isoc Out URB has finished it's transfer. Used
++     because several URBs can be finished before list is processed */
++  __u8  isoc_out_done;
++  
++  /* This field is used to pass information about the urb's current state
++     between the various interrupt handlers (thus marked volatile). */
++  volatile crisv10_urb_state_t urb_state;
++  
++  /* In Ctrl transfers consist of (at least) 3 packets: SETUP, IN and ZOUT.
++     When DMA8 sub-channel 2 has processed the SB list for this sequence we
++     get a interrupt. We also get a interrupt for In transfers and which
++     one of these interrupts that comes first depends of data size and device.
++     To be sure that we have got both interrupts before we complete the URB
++     we have these to flags that shows which part that has completed.
++     We can then check when we get one of the interrupts that if the other has
++     occured it's safe for us to complete the URB, otherwise we set appropriate
++     flag and do the completion when we get the other interrupt. */
++  volatile unsigned char ctrl_zout_done;
++  volatile unsigned char ctrl_rx_done;
++
++  /* Connection between the submitted urb and ETRAX epid number */
++  __u8 epid;
++  
++  /* The rx_data_list field is used for periodic traffic, to hold
++     received data for later processing in the the complete_urb functions,
++     where the data us copied to the urb's transfer_buffer. Basically, we
++     use this intermediate storage because we don't know when it's safe to
++     reuse the transfer_buffer (FIXME?). */
++  struct list_head rx_data_list;
++
++
++  /* The interval time rounded up to closest 2^N */
++  int interval;
++
++  /* Pool of EP descriptors needed if it's a INTR transfer.
++     Amount of EPs in pool correspons to how many INTR that should
++     be inserted in TxIntrEPList (max 128, defined by MAX_INTR_INTERVAL) */
++  struct USB_EP_Desc* intr_ep_pool[128];
++
++  /* The mount of EPs allocated for this INTR URB */
++  int intr_ep_pool_length;
++
++  /* Pointer to info struct if URB is scheduled to be finished later */
++  struct urb_later_data* later_data;
++};
++
++
++/* This struct is for passing data from the top half to the bottom half irq
++   handlers */
++struct crisv10_irq_reg {
++  struct usb_hcd* hcd;
++  __u32 r_usb_epid_attn;
++  __u8 r_usb_status;
++  __u16 r_usb_rh_port_status_1;
++  __u16 r_usb_rh_port_status_2;
++  __u32 r_usb_irq_mask_read;
++  __u32 r_usb_fm_number;
++  struct work_struct usb_bh;
++};
++
++
++/* This struct is for passing data from the isoc top half to the isoc bottom
++   half. */
++struct crisv10_isoc_complete_data {
++  struct usb_hcd *hcd;
++  struct urb *urb;
++  struct work_struct usb_bh;
++};
++
++/* Entry item for URB lists for each endpint */
++typedef struct urb_entry
++{
++	struct urb *urb;
++	struct list_head list;
++} urb_entry_t;
++
++/* ---------------------------------------------------------------------------
++   Virtual Root HUB
++   ------------------------------------------------------------------------- */
++/* destination of request */
++#define RH_INTERFACE               0x01
++#define RH_ENDPOINT                0x02
++#define RH_OTHER                   0x03
++
++#define RH_CLASS                   0x20
++#define RH_VENDOR                  0x40
++
++/* Requests: bRequest << 8 | bmRequestType */
++#define RH_GET_STATUS           0x0080
++#define RH_CLEAR_FEATURE        0x0100
++#define RH_SET_FEATURE          0x0300
++#define RH_SET_ADDRESS		0x0500
++#define RH_GET_DESCRIPTOR	0x0680
++#define RH_SET_DESCRIPTOR       0x0700
++#define RH_GET_CONFIGURATION	0x0880
++#define RH_SET_CONFIGURATION	0x0900
++#define RH_GET_STATE            0x0280
++#define RH_GET_INTERFACE        0x0A80
++#define RH_SET_INTERFACE        0x0B00
++#define RH_SYNC_FRAME           0x0C80
++/* Our Vendor Specific Request */
++#define RH_SET_EP               0x2000
++
++
++/* Hub port features */
++#define RH_PORT_CONNECTION         0x00
++#define RH_PORT_ENABLE             0x01
++#define RH_PORT_SUSPEND            0x02
++#define RH_PORT_OVER_CURRENT       0x03
++#define RH_PORT_RESET              0x04
++#define RH_PORT_POWER              0x08
++#define RH_PORT_LOW_SPEED          0x09
++#define RH_C_PORT_CONNECTION       0x10
++#define RH_C_PORT_ENABLE           0x11
++#define RH_C_PORT_SUSPEND          0x12
++#define RH_C_PORT_OVER_CURRENT     0x13
++#define RH_C_PORT_RESET            0x14
++
++/* Hub features */
++#define RH_C_HUB_LOCAL_POWER       0x00
++#define RH_C_HUB_OVER_CURRENT      0x01
++
++#define RH_DEVICE_REMOTE_WAKEUP    0x00
++#define RH_ENDPOINT_STALL          0x01
++
++/* Our Vendor Specific feature */
++#define RH_REMOVE_EP               0x00
++
++
++#define RH_ACK                     0x01
++#define RH_REQ_ERR                 -1
++#define RH_NACK                    0x00
++
++/* Field definitions for */
++
++#define USB_IN_command__eol__BITNR      0 /* command macros */
++#define USB_IN_command__eol__WIDTH      1
++#define USB_IN_command__eol__no         0
++#define USB_IN_command__eol__yes        1
++
++#define USB_IN_command__intr__BITNR     3
++#define USB_IN_command__intr__WIDTH     1
++#define USB_IN_command__intr__no        0
++#define USB_IN_command__intr__yes       1
++
++#define USB_IN_status__eop__BITNR       1 /* status macros. */
++#define USB_IN_status__eop__WIDTH       1
++#define USB_IN_status__eop__no          0
++#define USB_IN_status__eop__yes         1
++
++#define USB_IN_status__eot__BITNR       5
++#define USB_IN_status__eot__WIDTH       1
++#define USB_IN_status__eot__no          0
++#define USB_IN_status__eot__yes         1
++
++#define USB_IN_status__error__BITNR     6
++#define USB_IN_status__error__WIDTH     1
++#define USB_IN_status__error__no        0
++#define USB_IN_status__error__yes       1
++
++#define USB_IN_status__nodata__BITNR    7
++#define USB_IN_status__nodata__WIDTH    1
++#define USB_IN_status__nodata__no       0
++#define USB_IN_status__nodata__yes      1
++
++#define USB_IN_status__epid__BITNR      8
++#define USB_IN_status__epid__WIDTH      5
++
++#define USB_EP_command__eol__BITNR      0
++#define USB_EP_command__eol__WIDTH      1
++#define USB_EP_command__eol__no         0
++#define USB_EP_command__eol__yes        1
++
++#define USB_EP_command__eof__BITNR      1
++#define USB_EP_command__eof__WIDTH      1
++#define USB_EP_command__eof__no         0
++#define USB_EP_command__eof__yes        1
++
++#define USB_EP_command__intr__BITNR     3
++#define USB_EP_command__intr__WIDTH     1
++#define USB_EP_command__intr__no        0
++#define USB_EP_command__intr__yes       1
++
++#define USB_EP_command__enable__BITNR   4
++#define USB_EP_command__enable__WIDTH   1
++#define USB_EP_command__enable__no      0
++#define USB_EP_command__enable__yes     1
++
++#define USB_EP_command__hw_valid__BITNR 5
++#define USB_EP_command__hw_valid__WIDTH 1
++#define USB_EP_command__hw_valid__no    0
++#define USB_EP_command__hw_valid__yes   1
++
++#define USB_EP_command__epid__BITNR     8
++#define USB_EP_command__epid__WIDTH     5
++
++#define USB_SB_command__eol__BITNR      0 /* command macros. */
++#define USB_SB_command__eol__WIDTH      1
++#define USB_SB_command__eol__no         0
++#define USB_SB_command__eol__yes        1
++
++#define USB_SB_command__eot__BITNR      1
++#define USB_SB_command__eot__WIDTH      1
++#define USB_SB_command__eot__no         0
++#define USB_SB_command__eot__yes        1
++
++#define USB_SB_command__intr__BITNR     3
++#define USB_SB_command__intr__WIDTH     1
++#define USB_SB_command__intr__no        0
++#define USB_SB_command__intr__yes       1
++
++#define USB_SB_command__tt__BITNR       4
++#define USB_SB_command__tt__WIDTH       2
++#define USB_SB_command__tt__zout        0
++#define USB_SB_command__tt__in          1
++#define USB_SB_command__tt__out         2
++#define USB_SB_command__tt__setup       3
++
++
++#define USB_SB_command__rem__BITNR      8
++#define USB_SB_command__rem__WIDTH      6
++
++#define USB_SB_command__full__BITNR     6
++#define USB_SB_command__full__WIDTH     1
++#define USB_SB_command__full__no        0
++#define USB_SB_command__full__yes       1
++
++#endif
+diff -Nur linux-2.6.36.orig/lib/klist.c linux-2.6.36/lib/klist.c
+--- linux-2.6.36.orig/lib/klist.c	2010-10-20 22:30:22.000000000 +0200
++++ linux-2.6.36/lib/klist.c	2010-11-15 17:57:18.000000000 +0100
+@@ -60,7 +60,7 @@
+ {
+ 	knode->n_klist = klist;
+ 	/* no knode deserves to start its life dead */
+-	WARN_ON(knode_dead(knode));
++	//WARN_ON(knode_dead(knode));
+ }
+ 
+ static void knode_kill(struct klist_node *knode)

+ 11 - 0
target/m68k/sys-available/qemu-m68k

@@ -0,0 +1,11 @@
+config ADK_TARGET_SYSTEM_QEMU_M68K
+	bool "Qemu Emulator"
+	select ADK_m68k
+	select ADK_qemu_m68k
+	select ADK_TARGET_WITH_INPUT
+	select ADK_TARGET_WITH_PCI
+	select ADK_TARGET_WITH_HDD
+	select ADK_HARDWARE_QEMU
+	help
+	 Support for Qemu Emulator (M68K).
+

+ 8 - 0
target/m68k/sys-available/toolchain-m68k

@@ -0,0 +1,8 @@
+config ADK_TARGET_SYSTEM_TOOLCHAIN_M68K
+	bool "Toolchain only"
+	select ADK_m68k
+	select ADK_toolchain_m68k
+	select ADK_TOOLCHAIN
+	help
+	  Build a cris toolchain (m68k).
+

+ 5 - 0
target/m68k/target.mk

@@ -0,0 +1,5 @@
+include $(TOPDIR)/mk/kernel-ver.mk
+ARCH:=			m68k
+CPU_ARCH:=		$(ADK_TARGET_CPU_ARCH)
+TARGET_OPTIMIZATION:=	-O0 -pipe
+TARGET_CFLAGS_ARCH:=    $(ADK_TARGET_CFLAGS)

+ 244 - 0
target/m68k/uclibc.config

@@ -0,0 +1,244 @@
+#
+# Automatically generated make config: don't edit
+# Version: 0.9.32.1
+# Wed Jul 11 19:38:17 2012
+#
+# TARGET_alpha is not set
+# TARGET_arm is not set
+# TARGET_avr32 is not set
+# TARGET_bfin is not set
+# TARGET_cris is not set
+# TARGET_e1 is not set
+# TARGET_frv is not set
+# TARGET_h8300 is not set
+# TARGET_hppa is not set
+# TARGET_i386 is not set
+# TARGET_i960 is not set
+# TARGET_ia64 is not set
+TARGET_m68k=y
+# TARGET_microblaze is not set
+# TARGET_mips is not set
+# TARGET_nios is not set
+# TARGET_nios2 is not set
+# TARGET_powerpc is not set
+# TARGET_sh is not set
+# TARGET_sh64 is not set
+# TARGET_sparc is not set
+# TARGET_v850 is not set
+# TARGET_vax is not set
+# TARGET_x86_64 is not set
+# TARGET_xtensa is not set
+# TARGET_c6x is not set
+
+#
+# Target Architecture Features and Options
+#
+TARGET_ARCH="m68k"
+FORCE_OPTIONS_FOR_ARCH=y
+# CONFIG_CRIS is not set
+# CONFIG_CRISV32 is not set
+TARGET_SUBARCH=""
+
+#
+# Using ELF file format
+#
+ARCH_BIG_ENDIAN=y
+
+#
+# Using Big Endian
+#
+ARCH_HAS_MMU=y
+ARCH_USE_MMU=y
+UCLIBC_HAS_FLOATS=y
+UCLIBC_HAS_FPU=y
+DO_C99_MATH=y
+# DO_XSI_MATH is not set
+UCLIBC_HAS_FENV=y
+UCLIBC_HAS_LONG_DOUBLE_MATH=y
+KERNEL_HEADERS=""
+HAVE_DOT_CONFIG=y
+
+#
+# General Library Settings
+#
+# HAVE_NO_PIC is not set
+DOPIC=y
+# ARCH_HAS_NO_SHARED is not set
+# ARCH_HAS_NO_LDSO is not set
+HAVE_SHARED=y
+# FORCE_SHAREABLE_TEXT_SEGMENTS is not set
+LDSO_LDD_SUPPORT=y
+LDSO_CACHE_SUPPORT=y
+# LDSO_PRELOAD_ENV_SUPPORT is not set
+# LDSO_PRELOAD_FILE_SUPPORT is not set
+LDSO_BASE_FILENAME="ld.so"
+# UCLIBC_STATIC_LDCONFIG is not set
+LDSO_RUNPATH=y
+LDSO_SEARCH_INTERP_PATH=y
+UCLIBC_CTOR_DTOR=y
+# LDSO_GNU_HASH_SUPPORT is not set
+# HAS_NO_THREADS is not set
+LINUXTHREADS_OLD=y
+# LINUXTHREADS_NEW is not set
+# UCLIBC_HAS_THREADS_NATIVE is not set
+UCLIBC_HAS_THREADS=y
+PTHREADS_DEBUG_SUPPORT=y
+UCLIBC_HAS_SYSLOG=y
+UCLIBC_HAS_LFS=y
+# MALLOC is not set
+# MALLOC_SIMPLE is not set
+MALLOC_STANDARD=y
+MALLOC_GLIBC_COMPAT=y
+UCLIBC_DYNAMIC_ATEXIT=y
+COMPAT_ATEXIT=y
+UCLIBC_SUSV3_LEGACY=y
+# UCLIBC_SUSV3_LEGACY_MACROS is not set
+UCLIBC_SUSV4_LEGACY=y
+# UCLIBC_STRICT_HEADERS is not set
+# UCLIBC_HAS_STUBS is not set
+UCLIBC_HAS_SHADOW=y
+UCLIBC_HAS_PROGRAM_INVOCATION_NAME=y
+UCLIBC_HAS___PROGNAME=y
+UCLIBC_HAS_PTY=y
+ASSUME_DEVPTS=y
+UNIX98PTY_ONLY=y
+UCLIBC_HAS_GETPT=y
+UCLIBC_HAS_LIBUTIL=y
+UCLIBC_HAS_TM_EXTENSIONS=y
+UCLIBC_HAS_TZ_CACHING=y
+UCLIBC_HAS_TZ_FILE=y
+UCLIBC_HAS_TZ_FILE_READ_MANY=y
+UCLIBC_TZ_FILE_PATH="/etc/TZ"
+UCLIBC_FALLBACK_TO_ETC_LOCALTIME=y
+
+#
+# Advanced Library Settings
+#
+UCLIBC_PWD_BUFFER_SIZE=256
+UCLIBC_GRP_BUFFER_SIZE=256
+
+#
+# Support various families of functions
+#
+# UCLIBC_LINUX_MODULE_24 is not set
+UCLIBC_LINUX_SPECIFIC=y
+UCLIBC_HAS_GNU_ERROR=y
+UCLIBC_BSD_SPECIFIC=y
+UCLIBC_HAS_BSD_ERR=y
+# UCLIBC_HAS_OBSOLETE_BSD_SIGNAL is not set
+# UCLIBC_HAS_OBSOLETE_SYSV_SIGNAL is not set
+# UCLIBC_NTP_LEGACY is not set
+# UCLIBC_SV4_DEPRECATED is not set
+UCLIBC_HAS_REALTIME=y
+UCLIBC_HAS_ADVANCED_REALTIME=y
+UCLIBC_HAS_EPOLL=y
+# UCLIBC_HAS_XATTR is not set
+# UCLIBC_HAS_PROFILING is not set
+UCLIBC_HAS_CRYPT_IMPL=y
+UCLIBC_HAS_CRYPT=y
+UCLIBC_HAS_NETWORK_SUPPORT=y
+UCLIBC_HAS_SOCKET=y
+UCLIBC_HAS_IPV4=y
+UCLIBC_HAS_IPV6=y
+UCLIBC_HAS_RPC=y
+UCLIBC_HAS_FULL_RPC=y
+UCLIBC_HAS_REENTRANT_RPC=y
+UCLIBC_USE_NETLINK=y
+UCLIBC_SUPPORT_AI_ADDRCONFIG=y
+UCLIBC_HAS_BSD_RES_CLOSE=y
+UCLIBC_HAS_COMPAT_RES_STATE=y
+# UCLIBC_HAS_EXTRA_COMPAT_RES_STATE is not set
+UCLIBC_HAS_LIBRESOLV_STUB=y
+UCLIBC_HAS_LIBNSL_STUB=y
+
+#
+# String and Stdio Support
+#
+UCLIBC_HAS_STRING_GENERIC_OPT=y
+UCLIBC_HAS_STRING_ARCH_OPT=y
+UCLIBC_HAS_CTYPE_TABLES=y
+UCLIBC_HAS_CTYPE_SIGNED=y
+# UCLIBC_HAS_CTYPE_UNSAFE is not set
+UCLIBC_HAS_CTYPE_CHECKED=y
+# UCLIBC_HAS_CTYPE_ENFORCED is not set
+UCLIBC_HAS_WCHAR=y
+# UCLIBC_HAS_LOCALE is not set
+UCLIBC_HAS_HEXADECIMAL_FLOATS=y
+UCLIBC_HAS_GLIBC_CUSTOM_PRINTF=y
+UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS=9
+UCLIBC_HAS_SCANF_GLIBC_A_FLAG=y
+# UCLIBC_HAS_STDIO_BUFSIZ_NONE is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_256 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_512 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_1024 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_2048 is not set
+UCLIBC_HAS_STDIO_BUFSIZ_4096=y
+# UCLIBC_HAS_STDIO_BUFSIZ_8192 is not set
+UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE=y
+# UCLIBC_HAS_STDIO_BUILTIN_BUFFER_4 is not set
+# UCLIBC_HAS_STDIO_BUILTIN_BUFFER_8 is not set
+# UCLIBC_HAS_STDIO_SHUTDOWN_ON_ABORT is not set
+UCLIBC_HAS_STDIO_GETC_MACRO=y
+UCLIBC_HAS_STDIO_PUTC_MACRO=y
+UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION=y
+# UCLIBC_HAS_FOPEN_LARGEFILE_MODE is not set
+UCLIBC_HAS_FOPEN_EXCLUSIVE_MODE=y
+UCLIBC_HAS_GLIBC_CUSTOM_STREAMS=y
+UCLIBC_HAS_PRINTF_M_SPEC=y
+UCLIBC_HAS_ERRNO_MESSAGES=y
+# UCLIBC_HAS_SYS_ERRLIST is not set
+UCLIBC_HAS_SIGNUM_MESSAGES=y
+# UCLIBC_HAS_SYS_SIGLIST is not set
+UCLIBC_HAS_GNU_GETOPT=y
+UCLIBC_HAS_GNU_GETSUBOPT=y
+
+#
+# Big and Tall
+#
+UCLIBC_HAS_REGEX=y
+# UCLIBC_HAS_REGEX_OLD is not set
+UCLIBC_HAS_FNMATCH=y
+# UCLIBC_HAS_FNMATCH_OLD is not set
+UCLIBC_HAS_WORDEXP=y
+UCLIBC_HAS_NFTW=y
+UCLIBC_HAS_FTW=y
+# UCLIBC_HAS_FTS is not set
+UCLIBC_HAS_GLOB=y
+UCLIBC_HAS_GNU_GLOB=y
+# UCLIBC_HAS_UTMPX is not set
+
+#
+# Library Installation Options
+#
+RUNTIME_PREFIX="/"
+DEVEL_PREFIX="/usr/"
+MULTILIB_DIR="lib"
+HARDWIRED_ABSPATH=y
+
+#
+# Security options
+#
+UCLIBC_HAS_ARC4RANDOM=y
+# HAVE_NO_SSP is not set
+# UCLIBC_HAS_SSP is not set
+UCLIBC_BUILD_RELRO=y
+# UCLIBC_BUILD_NOW is not set
+UCLIBC_BUILD_NOEXECSTACK=y
+
+#
+# uClibc development/debugging options
+#
+CROSS_COMPILER_PREFIX=""
+UCLIBC_EXTRA_CFLAGS=""
+# DODEBUG is not set
+# DODEBUG_PT is not set
+DOSTRIP=y
+# DOASSERTS is not set
+# SUPPORT_LD_DEBUG is not set
+# SUPPORT_LD_DEBUG_EARLY is not set
+# UCLIBC_MALLOC_DEBUGGING is not set
+# UCLIBC_HAS_BACKTRACE is not set
+WARNINGS="-Wall"
+EXTRA_WARNINGS=y
+# DOMULTI is not set
+# UCLIBC_MJN3_ONLY is not set

+ 1 - 0
target/tarch.lst

@@ -1,6 +1,7 @@
 arm
 arm
 armeb
 armeb
 cris
 cris
+m68k
 mips
 mips
 mipsel
 mipsel
 ppc
 ppc