diff -urN linux-2.6.24.2/arch/arm/boot/compressed/head-xscale.S linux-2.6.24.2-vpac1/arch/arm/boot/compressed/head-xscale.S --- linux-2.6.24.2/arch/arm/boot/compressed/head-xscale.S 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/arch/arm/boot/compressed/head-xscale.S 2008-02-22 13:52:46.000000000 +0100 @@ -37,6 +37,11 @@ mov r7, #MACH_TYPE_COTULLA_IDP #endif +#ifdef CONFIG_MACH_VPAC270 + mov r7, #(MACH_TYPE_VPAC270 & 0xFF00) + add r7, r7, #(MACH_TYPE_VPAC270 & 0xFF) +#endif + #ifdef CONFIG_ARCH_IXP2000 mov r1, #-1 mov r0, #0xd6000000 diff -urN linux-2.6.24.2/arch/arm/configs/vpac270_defconfig linux-2.6.24.2-vpac1/arch/arm/configs/vpac270_defconfig --- linux-2.6.24.2/arch/arm/configs/vpac270_defconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/arch/arm/configs/vpac270_defconfig 2008-02-22 13:55:09.000000000 +0100 @@ -0,0 +1,1257 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.24.2-vpac1 +# Fri Feb 22 13:54:09 2008 +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_MMU=y +# CONFIG_NO_IOPORT is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ZONE_DMA=y +CONFIG_ARCH_MTD_XIP=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=16 +# CONFIG_CGROUPS is not set +# CONFIG_FAIR_GROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +# CONFIG_UID16 is not set +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +# CONFIG_SHMEM is not set +# CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_PNX4008 is not set +CONFIG_ARCH_PXA=y +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set + +# +# Intel PXA2xx/PXA3xx Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_MACH_LOGICPD_PXA270 is not set +# CONFIG_MACH_MAINSTONE is not set +CONFIG_MACH_VPAC270=y +# CONFIG_ARCH_PXA_IDP is not set +# CONFIG_PXA_SHARPSL is not set +# CONFIG_MACH_TRIZEPS4 is not set +# CONFIG_MACH_EM_X270 is not set +# CONFIG_MACH_ZYLONITE is not set +# CONFIG_MACH_ARMCORE is not set +CONFIG_PXA27x=y + +# +# Boot options +# + +# +# Power management +# + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_XSCALE=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5T=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_OUTER_CACHE is not set +CONFIG_IWMMXT=y +CONFIG_XSCALE_PMU=y + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +CONFIG_PCCARD=y +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_LOAD_CIS is not set +CONFIG_PCMCIA_IOCTL=y + +# +# PC-card bridges +# +CONFIG_PCMCIA_PXA2XX=y + +# +# Kernel Features +# +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_PREEMPT=y +CONFIG_HZ=100 +# CONFIG_AEABI is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x20000 +CONFIG_ZBOOT_ROM_BSS=0xa0800000 +CONFIG_ZBOOT_ROM=y +CONFIG_CMDLINE="mem=32M root=/dev/nfs ip=dhcp console=ttyS0,38400" +# CONFIG_KEXEC is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +# CONFIG_CPU_FREQ_DEBUG is not set +# CONFIG_CPU_FREQ_STAT is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_PXA=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set + +# +# Power management options +# +# CONFIG_PM is not set +CONFIG_SUSPEND_UP_POSSIBLE=y + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES 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_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_EXT=y +# CONFIG_MAC80211 is not set +CONFIG_IEEE80211=y +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_CRYPT_WEP=y +# CONFIG_IEEE80211_CRYPT_CCMP is not set +# CONFIG_IEEE80211_CRYPT_TKIP is not set +# CONFIG_IEEE80211_SOFTMAC is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +# CONFIG_MTD_CFI_I2 is not set +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_XIP is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PXA2XX is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +CONFIG_MTD_VPAC270=y +# CONFIG_MTD_SHARP_SL is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +# CONFIG_BLK_DEV is not set +# CONFIG_MISC_DEVICES is not set +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=2 +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +# CONFIG_IDE_GENERIC is not set +# CONFIG_BLK_DEV_PLATFORM is not set +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDE_VPAC270 is not set +# CONFIG_BLK_DEV_IDEDMA is not set +CONFIG_IDE_ARCH_OBSOLETE_INIT=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# 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=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +# CONFIG_SMC91X is not set +CONFIG_DM9000=y +# CONFIG_SMC911X is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_B44 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +CONFIG_WLAN_80211=y +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_LIBERTAS is not set +# CONFIG_HERMES is not set +# CONFIG_ATMEL is not set +# CONFIG_AIRO_CS is not set +# CONFIG_PCMCIA_WL3501 is not set +# CONFIG_USB_ZD1201 is not set +CONFIG_HOSTAP=y +# CONFIG_HOSTAP_FIRMWARE is not set +CONFIG_HOSTAP_CS=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_NET_PCMCIA is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER 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 + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +CONFIG_TOUCHSCREEN_UCB1400=y +# CONFIG_TOUCHSCREEN_USB_COMPOSITE 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_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_PXA=y +CONFIG_SERIAL_PXA_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +# CONFIG_R3964 is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_CHARDEV is not set + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_GPIO is not set +CONFIG_I2C_PXA=y +# CONFIG_I2C_PXA_SLAVE is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_DS1682 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_WATCHDOG is not set + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +CONFIG_FB_PXA=y +CONFIG_FB_PXA_ANALOG=y +# CONFIG_FB_PXA_TX14D14VM1BBA is not set +# CONFIG_FB_PXA_VGA is not set +CONFIG_FB_PXA_SVGA=y +# CONFIG_FB_PXA_XGA is not set +# CONFIG_FB_PXA_BPP8 is not set +CONFIG_FB_PXA_BPP16=y +# CONFIG_FB_PXA_PARAMETERS is not set +# CONFIG_FB_MBX is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=y + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +# CONFIG_SND_SEQUENCER is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +# CONFIG_SND_PCM_OSS_PLUGINS is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +CONFIG_SND_AC97_CODEC=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# ALSA ARM devices +# +CONFIG_SND_PXA2XX_PCM=y +CONFIG_SND_PXA2XX_AC97=y + +# +# USB devices +# +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set + +# +# PCMCIA devices +# +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_PDAUDIOCF is not set + +# +# System on Chip audio support +# +# CONFIG_SND_SOC is not set + +# +# SoC Audio support for SuperH +# + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set +CONFIG_AC97_BUS=y +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB_ARCH_HAS_EHCI is not set +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MON is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=y +# CONFIG_MMC_BLOCK_BOUNCE is not set +# CONFIG_SDIO_UART is not set + +# +# MMC/SD Host Controller Drivers +# +CONFIG_MMC_PXA=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +CONFIG_LEDS_VPAC270=y +# CONFIG_LEDS_GPIO is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_IDE_DISK is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +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 + +# +# I2C RTC drivers +# +CONFIG_RTC_DRV_DS1307=y +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_SA1100 is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set +# CONFIG_INSTRUMENTATION is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_FRAME_POINTER=y +# CONFIG_SAMPLES is not set +# CONFIG_DEBUG_USER is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_AUTHENC is not set +CONFIG_CRYPTO_HW=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff -urN linux-2.6.24.2/arch/arm/Kconfig linux-2.6.24.2-vpac1/arch/arm/Kconfig --- linux-2.6.24.2/arch/arm/Kconfig 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/arch/arm/Kconfig 2008-02-22 13:52:46.000000000 +0100 @@ -867,7 +867,7 @@ endmenu -if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX ) +if (ARCH_SA1100 || ARCH_PXA || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX ) menu "CPU Frequency scaling" @@ -883,6 +883,11 @@ depends on CPU_FREQ && (SA1100_ASSABET || SA1100_CERF || SA1100_PT_SYSTEM3) default y +config CPU_FREQ_PXA + bool + depends on CPU_FREQ && ARCH_PXA + default y + config CPU_FREQ_INTEGRATOR tristate "CPUfreq driver for ARM Integrator CPUs" depends on ARCH_INTEGRATOR && CPU_FREQ diff -urN linux-2.6.24.2/arch/arm/mach-pxa/cpu-pxa.c linux-2.6.24.2-vpac1/arch/arm/mach-pxa/cpu-pxa.c --- linux-2.6.24.2/arch/arm/mach-pxa/cpu-pxa.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/arch/arm/mach-pxa/cpu-pxa.c 2008-02-22 13:52:46.000000000 +0100 @@ -0,0 +1,417 @@ +/* + * linux/arch/arm/mach-pxa/cpu-pxa.c + * + * Copyright (C) 2002,2003 Intrinsyc Software + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * 31-Jul-2002 : Initial version [FB] + * 29-Jan-2003 : added PXA255 support [FB] + * 20-Apr-2003 : ported to v2.5 (Dustin McIntire, Sensoria Corp.) + * 11-Jan-2006 : v2.6, support for PXA27x processor up to 624MHz (Bill Reese, Hewlett Packard) + * + * Note: + * This driver may change the memory bus clock rate, but will not do any + * platform specific access timing changes... for example if you have flash + * memory connected to CS0, you will need to register a platform specific + * notifier which will adjust the memory access strobes to maintain a + * minimum strobe width. + * + */ + +#include +#include +#include +#include +#include + +#include + +#include + +/* + * This comes from generic.h in this directory. + */ +extern unsigned int get_clk_frequency_khz(int info); + +//#define DEBUG 7 + +#ifdef DEBUG + static unsigned int freq_debug = DEBUG; + module_param(freq_debug, int, 0644); + MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0"); +#else + #define freq_debug 0 +#endif + +typedef struct +{ + unsigned int khz; /* CPU frequency */ + unsigned int membus; /* memory bus frequency */ + unsigned int cccr; /* new CCLKCFG setting */ + unsigned int div2; /* alter memory controller settings to divide by 2 */ + unsigned int cclkcfg; /* new CCLKCFG setting */ +} pxa_freqs_t; + +/* Define the refresh period in mSec for the SDRAM and the number of rows */ +#define SDRAM_TREF 64 /* standard 64ms SDRAM */ +#if defined(CONFIG_MACH_H4700) || defined(CONFIG_ARCH_H2200) +#define SDRAM_ROWS 8192 /* hx4700 uses 2 64Mb DRAMs, 8912 rows */ +#else +#define SDRAM_ROWS 4096 /* 64MB=8192 32MB=4096 */ +#endif +#define MDREFR_DRI(x) (((x*SDRAM_TREF/SDRAM_ROWS - 31)/32)) + +#define CCLKCFG_TURBO 0x1 +#define CCLKCFG_FCS 0x2 +#define CCLKCFG_HALFTURBO 0x4 +#define CCLKCFG_FASTBUS 0x8 +#define MDREFR_DB2_MASK (MDREFR_K2DB2 | MDREFR_K1DB2) +#define MDREFR_DRI_MASK 0xFFF +#define PXA25x_CCLKCFG CCLKCFG_TURBO | CCLKCFG_FCS + +/* + * For the PXA27x: + * Control variables are A, L, 2N for CCCR; B, HT, T for CLKCFG. + * + * A = 0 => memory controller clock from table 3-7, + * A = 1 => memory controller clock = system bus clock + * Run mode frequency = 13 MHz * L + * Turbo mode frequency = 13 MHz * L * N + * System bus frequency = 13 MHz * L / (B + 1) + * System initialized by bootldr to: + * + * In CCCR: + * A = 1 + * L = 16 oscillator to run mode ratio + * 2N = 6 2 * (turbo mode to run mode ratio) + * + * In CCLKCFG: + * B = 1 Fast bus mode + * HT = 0 Half-Turbo mode + * T = 1 Turbo mode + * + * For now, just support some of the combinations in table 3-7 of + * PXA27x Processor Family Developer's Manual to simplify frequency + * change sequences. + * + * Specify 2N in the PXA27x_CCCR macro, not N! + */ +#define PXA27x_CCCR(A, L, N2) (A << 25 | N2 << 7 | L) +#define PXA27x_CCLKCFG(B, HT, T) (B << 3 | HT << 2 | CCLKCFG_FCS | T) + +/* + * Valid frequency assignments + */ +static pxa_freqs_t pxa2xx_freqs[] = +{ + /* CPU MEMBUS CCCR DIV2*/ +#if defined(CONFIG_PXA25x) +#if defined(CONFIG_PXA25x_ALTERNATE_FREQS) + { 99500, 99500, 0x121, 1, PXA25x_CCLKCFG}, /* run=99, turbo= 99, PXbus=50, SDRAM=50 */ + {199100, 99500, 0x221, 0, PXA25x_CCLKCFG}, /* run=99, turbo=199, PXbus=50, SDRAM=99 */ + {298500, 99500, 0x321, 0, PXA25x_CCLKCFG}, /* run=99, turbo=287, PXbus=50, SDRAM=99 */ + {298600, 99500, 0x1c1, 0, PXA25x_CCLKCFG}, /* run=199, turbo=287, PXbus=99, SDRAM=99 */ + {398100, 99500, 0x241, 0, PXA25x_CCLKCFG} /* run=199, turbo=398, PXbus=99, SDRAM=99 */ +#else + { 99500, 99500, 0x121, 1, PXA25x_CCLKCFG}, /* run= 99, turbo= 99, PXbus=50, SDRAM=50 */ + {132700, 132700, 0x123, 1, PXA25x_CCLKCFG}, /* run=133, turbo=133, PXbus=66, SDRAM=66 */ + {199100, 99500, 0x141, 0, PXA25x_CCLKCFG}, /* run=199, turbo=199, PXbus=99, SDRAM=99 */ + {265400, 132700, 0x143, 1, PXA25x_CCLKCFG}, /* run=265, turbo=265, PXbus=133, SDRAM=66 */ + {331800, 165900, 0x145, 1, PXA25x_CCLKCFG}, /* run=331, turbo=331, PXbus=166, SDRAM=83 */ + {398100, 99500, 0x161, 0, PXA25x_CCLKCFG} /* run=398, turbo=398, PXbus=196, SDRAM=99 */ +#endif +#elif defined(CONFIG_PXA27x) + {104000, 104000, PXA27x_CCCR(1, 8, 2), 0, PXA27x_CCLKCFG(1, 0, 1)}, + {156000, 104000, PXA27x_CCCR(1, 8, 6), 0, PXA27x_CCLKCFG(1, 1, 1)}, + {208000, 208000, PXA27x_CCCR(0, 16, 2), 1, PXA27x_CCLKCFG(0, 0, 1)}, + {312000, 208000, PXA27x_CCCR(1, 16, 3), 1, PXA27x_CCLKCFG(1, 0, 1)}, + {416000, 208000, PXA27x_CCCR(1, 16, 4), 1, PXA27x_CCLKCFG(1, 0, 1)}, + {520000, 208000, PXA27x_CCCR(1, 16, 5), 1, PXA27x_CCLKCFG(1, 0, 1)}, + {624000, 208000, PXA27x_CCCR(1, 16, 6), 1, PXA27x_CCLKCFG(1, 0, 1)} +#endif +}; +#define NUM_FREQS (sizeof(pxa2xx_freqs)/sizeof(pxa_freqs_t)) + +static struct cpufreq_frequency_table pxa2xx_freq_table[NUM_FREQS+1]; + +/* find a valid frequency point */ +static int pxa_verify_policy(struct cpufreq_policy *policy) +{ + int ret; + + ret=cpufreq_frequency_table_verify(policy, pxa2xx_freq_table); + + if(freq_debug) { + printk("Verified CPU policy: %dKhz min to %dKhz max\n", + policy->min, policy->max); + } + + return ret; +} + +static int pxa_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + int idx; + cpumask_t cpus_allowed, allowedcpuset; + int cpu = policy->cpu; + struct cpufreq_freqs freqs; + unsigned long flags; + unsigned int unused; + unsigned int preset_mdrefr, postset_mdrefr, cclkcfg; + + if(freq_debug) { + printk ("CPU PXA: target freq %d\n", target_freq); + printk ("CPU PXA: relation %d\n", relation); + } + + /* + * Save this threads cpus_allowed mask. + */ + cpus_allowed = current->cpus_allowed; + + /* + * Bind to the specified CPU. When this call returns, + * we should be running on the right CPU. + */ + cpus_clear (allowedcpuset); + cpu_set (cpu, allowedcpuset); + set_cpus_allowed(current, allowedcpuset); + BUG_ON(cpu != smp_processor_id()); + + /* Lookup the next frequency */ + if (cpufreq_frequency_table_target(policy, pxa2xx_freq_table, + target_freq, relation, &idx)) { + return -EINVAL; + } + + freqs.old = policy->cur; + freqs.new = pxa2xx_freqs[idx].khz; + freqs.cpu = policy->cpu; + if(freq_debug) { + printk(KERN_INFO "Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n", + freqs.new/1000, (pxa2xx_freqs[idx].div2) ? + (pxa2xx_freqs[idx].membus/2000) : + (pxa2xx_freqs[idx].membus/1000)); + } + + /* + * Tell everyone what we're about to do... + * you should add a notify client with any platform specific + * Vcc changing capability + */ + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* Calculate the next MDREFR. If we're slowing down the SDRAM clock + * we need to preset the smaller DRI before the change. If we're speeding + * up we need to set the larger DRI value after the change. + */ + preset_mdrefr = postset_mdrefr = MDREFR; + if((MDREFR & MDREFR_DRI_MASK) > MDREFR_DRI(pxa2xx_freqs[idx].membus)) { + preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK) | + MDREFR_DRI(pxa2xx_freqs[idx].membus); + } + postset_mdrefr = (postset_mdrefr & ~MDREFR_DRI_MASK) | + MDREFR_DRI(pxa2xx_freqs[idx].membus); + + /* If we're dividing the memory clock by two for the SDRAM clock, this + * must be set prior to the change. Clearing the divide must be done + * after the change. + */ + if(pxa2xx_freqs[idx].div2) { + /* + * Potentially speeding up memory clock, so slow down the memory + * before speeding up the clock. + */ + preset_mdrefr |= MDREFR_DB2_MASK | MDREFR_K0DB4; + preset_mdrefr &= ~MDREFR_K0DB2; + + postset_mdrefr |= MDREFR_DB2_MASK | MDREFR_K0DB4; + postset_mdrefr &= ~MDREFR_K0DB2; + } else { + /* + * Potentially slowing down memory clock. Wait until after the change + * to speed up the memory. + */ + postset_mdrefr &= ~MDREFR_DB2_MASK; + postset_mdrefr &= ~MDREFR_K0DB4; + postset_mdrefr |= MDREFR_K0DB2; + } + + cclkcfg = pxa2xx_freqs[idx].cclkcfg; + + if (freq_debug) { + printk (KERN_INFO "CPU PXA writing 0x%08x to CCCR\n", + pxa2xx_freqs[idx].cccr); + printk (KERN_INFO "CPU PXA writing 0x%08x to CCLKCFG\n", + pxa2xx_freqs[idx].cclkcfg); + printk (KERN_INFO "CPU PXA writing 0x%08x to MDREFR before change\n", + preset_mdrefr); + printk (KERN_INFO "CPU PXA writing 0x%08x to MDREFR after change\n", + postset_mdrefr); + } + + local_irq_save(flags); + + /* Set new the CCCR */ + CCCR = pxa2xx_freqs[idx].cccr; + + /* + * Should really set both of PMCR[xIDAE] while changing the core frequency + */ + + /* + * TODO: On the PXA27x: If we're setting half-turbo mode and changing the + * core frequency at the same time we must split it up into two operations. + * The current values in the pxa2xx_freqs table don't do this, so the code + * is unimplemented. + */ + + __asm__ __volatile__(" \ + ldr r4, [%1] ; /* load MDREFR */ \ + b 2f ; \ + .align 5 ; \ +1: \ + str %3, [%1] ; /* preset the MDREFR */ \ + mcr p14, 0, %2, c6, c0, 0 ; /* set CCLKCFG[FCS] */ \ + str %4, [%1] ; /* postset the MDREFR */ \ + \ + b 3f ; \ +2: b 1b ; \ +3: nop ; \ + " + : "=&r" (unused) + : "r" (&MDREFR), "r" (cclkcfg), \ + "r" (preset_mdrefr), "r" (postset_mdrefr) + : "r4", "r5"); + local_irq_restore(flags); + + if (freq_debug) { + printk (KERN_INFO "CPU PXA Frequency change successful\n"); + printk (KERN_INFO "CPU PXA new CCSR 0x%08x\n", CCSR); + } + + /* + * Restore the CPUs allowed mask. + */ + set_cpus_allowed(current, cpus_allowed); + + /* + * Tell everyone what we've just done... + * you should add a notify client with any platform specific + * SDRAM refresh timer adjustments + */ + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +static int pxa_cpufreq_init(struct cpufreq_policy *policy) +{ + cpumask_t cpus_allowed, allowedcpuset; + unsigned int cpu = policy->cpu; + int i; + unsigned int cclkcfg; + + cpus_allowed = current->cpus_allowed; + + cpus_clear (allowedcpuset); + cpu_set (cpu, allowedcpuset); + set_cpus_allowed(current, allowedcpuset); + BUG_ON(cpu != smp_processor_id()); + + /* set default governor and cpuinfo */ + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */ + policy->cur = get_clk_frequency_khz(0); /* current freq */ + + /* Generate the cpufreq_frequency_table struct */ + for(i=0;icpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + BUG_ON(cpu != smp_processor_id()); + + cur_freq = get_clk_frequency_khz(0); + + set_cpus_allowed(current, cpumask_saved); + + return cur_freq; +} + +static struct cpufreq_driver pxa_cpufreq_driver = { + .verify = pxa_verify_policy, + .target = pxa_set_target, + .init = pxa_cpufreq_init, + .get = pxa_cpufreq_get, +#if defined(CONFIG_PXA25x) + .name = "PXA25x", +#elif defined(CONFIG_PXA27x) + .name = "PXA27x", +#endif +}; + +static int __init pxa_cpu_init(void) +{ + return cpufreq_register_driver(&pxa_cpufreq_driver); +} + +static void __exit pxa_cpu_exit(void) +{ + cpufreq_unregister_driver(&pxa_cpufreq_driver); +} + + +MODULE_AUTHOR ("Intrinsyc Software Inc."); +MODULE_DESCRIPTION ("CPU frequency changing driver for the PXA architecture"); +MODULE_LICENSE("GPL"); +module_init(pxa_cpu_init); +module_exit(pxa_cpu_exit); + diff -urN linux-2.6.24.2/arch/arm/mach-pxa/Kconfig linux-2.6.24.2-vpac1/arch/arm/mach-pxa/Kconfig --- linux-2.6.24.2/arch/arm/mach-pxa/Kconfig 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/arch/arm/mach-pxa/Kconfig 2008-02-22 13:52:46.000000000 +0100 @@ -36,6 +36,11 @@ bool "Intel HCDDBBVA0 Development Platform" select PXA27x +config MACH_VPAC270 + bool "Voipac PXA270 Module" + select PXA27x + select IWMMXT + config ARCH_PXA_IDP bool "Accelent Xscale IDP" select PXA25x diff -urN linux-2.6.24.2/arch/arm/mach-pxa/Makefile linux-2.6.24.2-vpac1/arch/arm/mach-pxa/Makefile --- linux-2.6.24.2/arch/arm/mach-pxa/Makefile 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/arch/arm/mach-pxa/Makefile 2008-02-22 13:52:46.000000000 +0100 @@ -21,6 +21,7 @@ obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o obj-$(CONFIG_MACH_POODLE) += poodle.o corgi_ssp.o obj-$(CONFIG_MACH_TOSA) += tosa.o +obj-$(CONFIG_MACH_VPAC270) += vpac270.o obj-$(CONFIG_MACH_EM_X270) += em-x270.o ifeq ($(CONFIG_MACH_ZYLONITE),y) @@ -40,6 +41,9 @@ obj-$(CONFIG_LEDS) += $(led-y) +# CPU Frequency scaling +obj-$(CONFIG_CPU_FREQ_PXA) += cpu-pxa.o + # Misc features obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_PXA_SSP) += ssp.o diff -urN linux-2.6.24.2/arch/arm/mach-pxa/vpac270.c linux-2.6.24.2-vpac1/arch/arm/mach-pxa/vpac270.c --- linux-2.6.24.2/arch/arm/mach-pxa/vpac270.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/arch/arm/mach-pxa/vpac270.c 2008-02-22 23:26:31.000000000 +0100 @@ -0,0 +1,437 @@ + /* + * linux/arch/arm/mach-pxa/vpac270.c + * + * Support for Voipac PXA270 module + * + * Copyright (c) 2006 Voipac Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "generic.h" + +#include + + +static void __init vpac270_init_irq(void) +{ + pxa27x_init_irq(); + + /* setup extra vpac270 irqs */ + set_irq_type(VPAC270_ETH_IRQ, IRQT_RISING); + set_irq_type(VPAC270_IDE_IRQ, IRQT_RISING); +} + +static struct resource dm9000_resources[] = { + [0] = { + .start = (VPAC270_ETH_PHYS + 0x300), + .end = (VPAC270_ETH_PHYS + 0x300 + VPAC270_ETH_SIZE - 1), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = (VPAC270_ETH_IRQ), + .end = (VPAC270_ETH_IRQ), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct dm9000_plat_data dm9000_setup = { + .flags = 0 //DM9000_PLATF_16BITONLY +}; + +static struct platform_device dm9000_device = { + .name = "dm9000", + .id = 0, + .num_resources = ARRAY_SIZE(dm9000_resources), + .resource = dm9000_resources, + .dev = { + .platform_data = &dm9000_setup, + } +}; +#ifdef CONFIG_SPI_PXA2XX +static struct resource pxa_ssp_resources[] = { + [0] = { + .start = __PREG(SSCR0_P(1)), + .end = __PREG(SSCR0_P(1)) + 0x14, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SSP, + .end = IRQ_SSP, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct pxa2xx_spi_master pxa_ssp_master_info = { + .ssp_type = PXA25x_SSP, + .clock_enable = CKEN_SSP, + .num_chipselect = 1, +}; + +static struct platform_device vpac270_ssp_device = { + .name = "pxa2xx-spi", + .id = 1, + .resource = pxa_ssp_resources, + .num_resources = ARRAY_SIZE(pxa_ssp_resources), + .dev = { + .platform_data = &pxa_ssp_master_info, + }, +}; +#endif +#ifdef CONFIG_SND_PXA2XX_AC97 +static struct platform_device pxa_audio_device = { + .name = "pxa2xx-ac97", + .id = -1, +}; +#endif +#ifdef CONFIG_SERIO_VPAC270 +static struct platform_device vpac270kb_device = { + .name = "vpac270ps2", + .id = 0, +}; + +static struct platform_device vpac270ms_device = { + .name = "vpac270ps2", + .id = 1, +}; +#endif +#ifdef CONFIG_LEDS_VPAC270 +static struct platform_device vpac270led_device = { + .name = "vpac270-led", + .id = -1, +}; +#endif +static struct platform_device *devices[] __initdata = { + &dm9000_device, +#ifdef CONFIG_SND_PXA2XX_AC97 + &pxa_audio_device, +#endif +#ifdef CONFIG_SPI_PXA2XX + &vpac270_ssp_device, +#endif +#ifdef CONFIG_SERIO_VPAC270 + &vpac270ms_device, + &vpac270kb_device, +#endif +#ifdef CONFIG_LEDS_VPAC270 + &vpac270led_device, +#endif +}; + +/* + * MMC/SD Device + * + */ +static struct pxamci_platform_data vpac270_mci_platform_data; + +static int vpac270_mci_init(struct device *dev, irqreturn_t (*detect_int)(int, void *), void *data) +{ + int err; + + printk("Voipac PXA270 MMC/SD setup "); + /* setup GPIO for PXA2xx MMC controller */ + pxa_gpio_mode(GPIO32_MMCCLK_MD); + pxa_gpio_mode(GPIO112_MMCCMD_MD); + pxa_gpio_mode(GPIO92_MMCDAT0_MD); + pxa_gpio_mode(GPIO109_MMCDAT1_MD); + pxa_gpio_mode(GPIO110_MMCDAT2_MD); + pxa_gpio_mode(GPIO111_MMCDAT3_MD); + + pxa_gpio_mode(GPIO_MMC_CD_IRQ | GPIO_IN); + + vpac270_mci_platform_data.detect_delay = msecs_to_jiffies(250); + + err = request_irq(VPAC270_MMC_CD_IRQ, detect_int, 0, + "MMC card detect", data); + if (err) { + printk(KERN_ERR "vpac270_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); + return -1; + } + + set_irq_type(VPAC270_MMC_CD_IRQ, IRQT_BOTHEDGE); + + printk("done.\n"); + return 0; +} + +static struct pxamci_platform_data vpac270_mci_platform_data = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .init = vpac270_mci_init, +}; + +#ifdef CONFIG_FB_PXA + +#ifdef CONFIG_FB_PXA_BPP8 +#define FB_PXA_BPP 8 +#else +#define FB_PXA_BPP 16 +#endif + +static struct pxafb_mode_info vpac270_fb_mode_info[] __initdata = { +#if defined(CONFIG_FB_PXA_TX14D14VM1BBA) +/* VGA 640x480 18bit, pclk=26MHz */ +{ + .pixclock = 57693, // PCD=3 + .xres = 640, + .yres = 480, + .bpp = 8, + .hsync_len = 32, + .left_margin = 144, + .right_margin = 32, + .vsync_len = 2, + .upper_margin = 13, + .lower_margin = 30, + .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, +}, +#elif defined(CONFIG_FB_PXA_VGA) +/* VGA 640x480 16bit, pclk=26MHz */ +{ + .pixclock = 57693, // PCD=3 + .xres = 640, + .yres = 480, + .bpp = FB_PXA_BPP, + .hsync_len = 64, + .left_margin = 96, + .right_margin = 48, + .vsync_len = 2, + .upper_margin = 33, + .lower_margin = 10, + .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, +}, +#elif defined(CONFIG_FB_PXA_SVGA) +/* SVGA 800x600 16bit, pclk=34.6MHz */ +{ + .pixclock = 38462, // PCD=2 + .xres = 800, + .yres = 600, + .bpp = FB_PXA_BPP, + .hsync_len = 8, + .left_margin = 128, + .right_margin = 48, + .vsync_len = 1, + .upper_margin = 33, + .lower_margin = 1, + .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, +}, +#elif defined(CONFIG_FB_PXA_XGA) +/* XGA 1024x768 16bit, pclk=52.0MHz */ +{ + .pixclock = 19231, // PCD=1 + .xres = 1024, + .yres = 768, + .bpp = FB_PXA_BPP, + .hsync_len = 63, + .left_margin = 220, + .right_margin = 8, + .vsync_len = 1, + .upper_margin = 33, + .lower_margin = 2, + .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, +}, +#endif +}; + +static struct pxafb_mach_info vpac270_fb_mach_info __initdata = { + .modes = vpac270_fb_mode_info, + .num_modes = ARRAY_SIZE(vpac270_fb_mode_info), + .lccr0 = 0x043008f8, + .lccr3 = 0x0040ff00, +#if defined(CONFIG_FB_PXA_TX14D14VM1BBA) + .lccr4 = LCCR4_PAL_FOR_2, +#else + .lccr4 = LCCR4_PAL_FOR_0, +#endif +}; +#endif // CONFIG_FB_PXA + +static int vpac270_ohci_init(struct device *dev) +{ + /* setup Port1 GPIO pin. */ + pxa_gpio_mode( 88 | GPIO_ALT_FN_1_IN); /* USBHPWR1 */ + pxa_gpio_mode( 89 | GPIO_ALT_FN_2_OUT); /* USBHPEN1 */ + pxa_gpio_mode(119 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(120 | GPIO_ALT_FN_2_OUT); + + /* Set the Power Control Polarity Low and Power Sense + Polarity Low to active low. */ + UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) & + ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE); + + UP2OCR = UP2OCR_HXS | UP2OCR_HXOE | UP2OCR_DPPDE | UP2OCR_DMPDE; + + return 0; +} + +static struct pxaohci_platform_data vpac270_ohci_platform_data = { + .port_mode = PMM_GLOBAL_MODE, //PMM_PERPORT_MODE, PMM_NPS_MODE, + .init = vpac270_ohci_init, +}; + +/* USB Device Controller */ + +static int +udc_detect(void) +{ + printk ("UDC detect\n"); +// if (core_funcs.udc_detect != NULL) +// return core_funcs.udc_detect(); +// else + return 0; +} + +static void +udc_enable(int cmd) +{ + switch (cmd) + { + case PXA2XX_UDC_CMD_DISCONNECT: + printk (KERN_NOTICE "UDC cmd disconnect\n"); + + UP2OCR = (UP2OCR | UP2OCR_HXS| UP2OCR_HXOE | UP2OCR_DPPDE | UP2OCR_DMPDE) & + ~(UP2OCR_DPPUE | UP2OCR_DMPUE | UP2OCR_DPPUBE | UP2OCR_DMPUBE); + break; + + case PXA2XX_UDC_CMD_CONNECT: + printk (KERN_NOTICE "UDC cmd connect\n"); + + UP2OCR = (UP2OCR | UP2OCR_HXOE | UP2OCR_DPPUE) & + ~(UP2OCR_HXS | UP2OCR_DMPUE | UP2OCR_DPPUBE | + UP2OCR_DMPUBE | UP2OCR_DPPDE | UP2OCR_DMPDE); + break; + } +} + +static struct pxa2xx_udc_mach_info hx4700_udc_mach_info = { + .udc_is_connected = udc_detect, + .udc_command = udc_enable, +}; + +static struct i2c_board_info __initdata vpac270_i2c_devices[] = { + { + I2C_BOARD_INFO("rtc-ds1307", 0x68), + .type = "ds1339", + }, +}; + +static void __init vpac270_init(void) +{ + /* reset UCB1400 */ + GPSR2 &= ~(1u << 31); + pxa_gpio_mode(GPIO_AC97_RESET | GPIO_OUT); + udelay(12); + pxa_set_mci_info(&vpac270_mci_platform_data); + platform_add_devices(devices, ARRAY_SIZE(devices)); + i2c_register_board_info(0, vpac270_i2c_devices, ARRAY_SIZE(vpac270_i2c_devices)); +#ifdef CONFIG_FB_PXA + set_pxa_fb_info(&vpac270_fb_mach_info); +#if defined(CONFIG_FB_PXA_TX14D14VM1BBA) + pxa_gpio_mode(86 | GPIO_ALT_FN_2_OUT); + pxa_gpio_mode(87 | GPIO_ALT_FN_2_OUT); + LCCR4 = 0x800b0000; +#else + LCCR4 = 0x800a0000; +#endif +#endif + pxa_set_ohci_info(&vpac270_ohci_platform_data); + pxa_set_udc_info( &hx4700_udc_mach_info ); + + GPDR(VPAC270_LCD_BLO_GPIO) |= GPIO_bit(VPAC270_LCD_BLO_GPIO); + GPSR(VPAC270_LCD_BLO_GPIO) |= GPIO_bit(VPAC270_LCD_BLO_GPIO); + +} + +static struct map_desc vpac270_io_desc[] __initdata = { + /* virtual physical length type */ +/*{ VPAC270_FLASH, VPAC270_FLASH_PHYS, VPAC270_FLASH_SIZE, MT_DEVICE }, + { VPAC270_ETH_BASE, VPAC270_ETH_PHYS, VPAC270_ETH_SIZE, MT_DEVICE },*/ +// { 0xf0000000, __phys_to_pfn(0x0c000000), 0x04000000, MT_DEVICE }, +}; + +static void __init vpac270_map_io(void) +{ + pxa_map_io(); + iotable_init(vpac270_io_desc, ARRAY_SIZE(vpac270_io_desc)); + + /* enabling FFUART */ + CKEN |= CKEN_FFUART; + pxa_gpio_mode(GPIO34_FFRXD_MD); + pxa_gpio_mode(GPIO100_FFCTS_MD); + pxa_gpio_mode(GPIO10_FFDCD_MD); + pxa_gpio_mode(GPIO33_FFDSR_MD); + pxa_gpio_mode(GPIO38_FFRI_MD); + pxa_gpio_mode(GPIO39_FFTXD_MD); + pxa_gpio_mode(GPIO40_FFDTR_MD); + pxa_gpio_mode(GPIO27_FFRTS_MD); + + /* enabling BTUART */ + CKEN |= CKEN_BTUART; + pxa_gpio_mode(GPIO42_BTRXD_MD); + pxa_gpio_mode(GPIO43_BTTXD_MD); + pxa_gpio_mode(GPIO44_BTCTS_MD); + pxa_gpio_mode(GPIO45_BTRTS_MD); + + /* This is for the Davicom chip select */ + pxa_gpio_mode(GPIO78_nCS_2_MD); + + /* bring hdd out of reset */ + GPCR(GPIO_PCMCIA1_RESET) |= GPIO_bit(GPIO_PCMCIA1_RESET); // disable reset + + /* setup sleep mode values */ + PWER = 0x00000002; + PFER = 0x00000000; + PRER = 0x00000002; + PGSR0 = 0x00008000; + PGSR1 = 0x003F0202; + PGSR2 = 0x0001C000; + PCFR |= PCFR_OPDE; +} + +MACHINE_START(VPAC270, "Voipac PXA270 Module") + /* Maintainer: Voipac Technologies */ + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = 0xa0000100, + .map_io = vpac270_map_io, + .init_irq = vpac270_init_irq, + .timer = &pxa_timer, + .init_machine = vpac270_init, +MACHINE_END + diff -urN linux-2.6.24.2/arch/arm/Makefile linux-2.6.24.2-vpac1/arch/arm/Makefile --- linux-2.6.24.2/arch/arm/Makefile 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/arch/arm/Makefile 2008-02-22 13:52:46.000000000 +0100 @@ -20,7 +20,7 @@ # Do not use arch/arm/defconfig - it's always outdated. # Select a platform tht is kept up-to-date -KBUILD_DEFCONFIG := versatile_defconfig +KBUILD_DEFCONFIG := vpac270_defconfig # defines filename extension depending memory manement type. ifeq ($(CONFIG_MMU),) diff -urN linux-2.6.24.2/drivers/cpufreq/Kconfig linux-2.6.24.2-vpac1/drivers/cpufreq/Kconfig --- linux-2.6.24.2/drivers/cpufreq/Kconfig 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/cpufreq/Kconfig 2008-02-22 13:52:46.000000000 +0100 @@ -19,7 +19,7 @@ if CPU_FREQ config CPU_FREQ_TABLE - tristate + def_tristate m config CPU_FREQ_DEBUG bool "Enable CPUfreq debugging" @@ -58,7 +58,7 @@ choice prompt "Default CPUFreq governor" - default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110 + default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110 || CPU_FREQ_PXA27x default CPU_FREQ_DEFAULT_GOV_PERFORMANCE help This option sets which CPUFreq governor shall be loaded at diff -urN linux-2.6.24.2/drivers/ide/arm/Makefile linux-2.6.24.2-vpac1/drivers/ide/arm/Makefile --- linux-2.6.24.2/drivers/ide/arm/Makefile 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/ide/arm/Makefile 2008-02-22 13:52:46.000000000 +0100 @@ -2,5 +2,6 @@ obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o obj-$(CONFIG_BLK_DEV_IDE_BAST) += bast-ide.o +obj-$(CONFIG_BLK_DEV_IDE_VPAC270) += vpac270-ide.o EXTRA_CFLAGS := -Idrivers/ide diff -urN linux-2.6.24.2/drivers/ide/arm/vpac270-ide.c linux-2.6.24.2-vpac1/drivers/ide/arm/vpac270-ide.c --- linux-2.6.24.2/drivers/ide/arm/vpac270-ide.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/ide/arm/vpac270-ide.c 2008-02-22 13:52:46.000000000 +0100 @@ -0,0 +1,286 @@ +/* linux/drivers/ide/arm/vpac270-ide.c + * + * Copyright (c) 2006 Voipac Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * +*/ + +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/* list of registered interfaces */ +static ide_hwif_t *vpac270_hwif; + +#define IDE_BASE_PHYS 0x0c000000 +//#define DMA_IRQ_DETECT IRQ_GPIO(80) +#define GPIO80_DREQ_1_MD (80 | GPIO_ALT_FN_1_IN) + +static void vpac270_set_dma_mode(ide_drive_t *drive, u8 xfer_mode) +{ + int cycle_time = 0, use_dma_info = 0; + + switch (xfer_mode) { + case XFER_MW_DMA_2: + cycle_time = 120; + use_dma_info = 1; + break; + + case XFER_MW_DMA_1: + cycle_time = 250; + use_dma_info = 1; + break; + + case XFER_MW_DMA_0: + cycle_time = 480; + break; + + case XFER_SW_DMA_2: + case XFER_SW_DMA_1: + case XFER_SW_DMA_0: + cycle_time = 480; + break; + + default: + return; + } + + if (use_dma_info && drive->id->eide_dma_time > cycle_time) + cycle_time = drive->id->eide_dma_time; + + drive->drive_data = cycle_time; + + printk("%s: %s selected (peak %dMB/s)\n", drive->name, + ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data); +} + +static void vpac270_dma_host_off(ide_drive_t *drive) +{ +} + +static void vpac270_dma_off_quietly(ide_drive_t *drive) +{ + drive->using_dma = 0; +} + +static void vpac270_dma_host_on(ide_drive_t *drive) +{ +} + +static int vpac270_dma_on(ide_drive_t *drive) +{ + drive->using_dma = 1; + return 0; +} + +static int vpac270_dma_setup(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct request *rq = hwif->hwgroup->rq; + + blk_queue_max_segment_size( drive->queue, (DCMD_LENGTH & 0xfffffe00) ); + ide_map_sg(drive, rq); + + hwif->sg_dma_direction = (rq_data_dir(rq) == READ)? + DMA_FROM_DEVICE : DMA_TO_DEVICE; + + if( hwif->sg_nents > 0) + { + int i = 0; + int dma = hwif->dma; + struct scatterlist *sg = hwif->sg_table; + + pxa_dma_desc *ddadr = (void *) hwif->dmatable_dma; + pxa_dma_desc *ddptr = (void *) hwif->dmatable_cpu; + + DCSR(dma) = 0; + + do + { + u32 length = sg->length; + + sg->dma_address = dma_map_page( NULL, sg->page_link, sg->offset, + length, hwif->sg_dma_direction); + + ddptr->ddadr = (u32) ++ddadr; // next DDADR + + if(hwif->sg_dma_direction == DMA_FROM_DEVICE) + { + ddptr->dsadr = 0xc000020; // DSADR + ddptr->dtadr = sg->dma_address; // DTADR + ddptr->dcmd = (DCMD_INCTRGADDR | DCMD_BURST32 | DCMD_FLOWSRC | + DCMD_WIDTH2 | (DCMD_LENGTH & length)); + } + else + { + ddptr->dsadr = sg->dma_address; // DSADR + ddptr->dtadr = 0xc000020; // DTADR + ddptr->dcmd = (DCMD_INCSRCADDR | DCMD_BURST32 | DCMD_FLOWTRG | + DCMD_WIDTH2 | (DCMD_LENGTH & length)); + } + sg++; + } + while( ++i < hwif->sg_nents && ddptr++); + + ddptr->ddadr = DDADR_STOP; + + DDADR(dma) = hwif->dmatable_dma; + + DRQSR1 = DRQSR_REQCLR; + DRCMR1 = dma | DRCMR_MAPVLD; + + DCSR(dma) = DCSR_RUN; + drive->waiting_for_dma = 1; + } + return 0; +} + +static void vpac270_dma_exec_cmd(ide_drive_t *drive, u8 cmd) +{ + ide_execute_command(drive, cmd, &ide_dma_intr, 2 * WAIT_CMD, NULL); +} + +static void vpac270_dma_start(ide_drive_t *drive) +{ +} + +static int vpac270_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + int dma = hwif->dma; + + drive->waiting_for_dma = 0; + + while (!(DCSR(dma) & DCSR_STOPSTATE)) + cpu_relax(); + DCSR(dma) = 0; + + dma_unmap_sg( NULL, hwif->sg_table, hwif->sg_nents, + hwif->sg_dma_direction); + return 0; +} + +static int vpac270_dma_test_irq(ide_drive_t *drive) +{ + return (GPLR(GPIO_IDE_IRQ) & GPIO_bit(GPIO_IDE_IRQ)); +} + +static void vpac270_dma_timeout(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + int dma = hwif->dma; +printk("%s:%d\n",__FUNCTION__,__LINE__); +printk("%s:%d DCSR(%d)=%08x\n",__FUNCTION__,__LINE__,dma,DCSR(dma)); + printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name); + + if (vpac270_dma_test_irq(drive)) + return; + + ide_dump_status(drive, "DMA timeout", + HWIF(drive)->INB(IDE_STATUS_REG)); + + vpac270_dma_end(drive); +} + +static void vpac270_dma_lostirq(ide_drive_t *drive) +{ +printk("%s:%d\n",__FUNCTION__,__LINE__); + printk(KERN_ERR "%s: IRQ lost\n", drive->name); +} + +static void vpac270_pxa_dma_irq(int dma, void *dummy) +{ +printk("%s:%d DCSR(%d)=%08x\n",__FUNCTION__,__LINE__,dma,DCSR(dma)); +printk("%s:%d DRQSR1=0x%08x\n",__FUNCTION__,__LINE__,DRQSR1); + + DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; +} + +static void vpac270_dma_init(ide_hwif_t *hwif) +{ + printk(" %s: SG-DMA", hwif->name); + + pxa_gpio_mode(GPIO80_DREQ_1_MD); + + hwif->mwdma_mask = 7; + hwif->swdma_mask = 7; + + hwif->dmatable_cpu = NULL; + hwif->dmatable_dma = 0; + hwif->set_dma_mode = vpac270_set_dma_mode; + + hwif->dma_host_off = vpac270_dma_host_off; + hwif->dma_off_quietly = vpac270_dma_off_quietly; + hwif->dma_host_on = vpac270_dma_host_on; + hwif->ide_dma_on = vpac270_dma_on; + hwif->dma_setup = vpac270_dma_setup; + hwif->dma_exec_cmd = vpac270_dma_exec_cmd; + hwif->dma_start = vpac270_dma_start; + hwif->ide_dma_end = vpac270_dma_end; + hwif->ide_dma_test_irq = vpac270_dma_test_irq; + hwif->dma_timeout = vpac270_dma_timeout; + hwif->dma_lost_irq = vpac270_dma_lostirq; + + hwif->noprobe = 0; + hwif->chipset = ide_unknown; + hwif->channel = 0; + hwif->serialized = 1; + hwif->dma = pxa_request_dma( hwif->name, DMA_PRIO_LOW, + vpac270_pxa_dma_irq, NULL); + + hwif->dmatable_cpu = dma_alloc_coherent( NULL, (PRD_ENTRIES * 4 * sizeof(u32)), + &hwif->dmatable_dma, GFP_ATOMIC); + + printk(" capable, dma=%d\n", hwif->dma); +} + +static int __init vpac270_ide_init(void) +{ + u32 base = (u32) ioremap( IDE_BASE_PHYS, 0x200);; + + printk("Voipac PXA270 IDE driver, (c) 2006 Voipac Technologies\n"); + + if( base) + { + int i; + hw_regs_t hw; + + memset(&hw, 0, sizeof(hw)); + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) + hw.io_ports[i] = (base + 0x120 + 2*i); + + hw.io_ports[IDE_CONTROL_OFFSET] = (base + 0x15c); + hw.irq = VPAC270_IDE_IRQ; + + ide_register_hw(&hw, NULL, 0, &vpac270_hwif); + + vpac270_dma_init( vpac270_hwif); + } + return 0; +} + +module_init(vpac270_ide_init); + +MODULE_AUTHOR("Voipac Technologies "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Voipac PXA270 IDE driver"); + diff -urN linux-2.6.24.2/drivers/ide/Kconfig linux-2.6.24.2-vpac1/drivers/ide/Kconfig --- linux-2.6.24.2/drivers/ide/Kconfig 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/ide/Kconfig 2008-02-22 13:52:46.000000000 +0100 @@ -930,6 +930,11 @@ help Enables the H8300 IDE driver. +config BLK_DEV_IDE_VPAC270 + tristate "Voipac PXA270 IDE support" + depends on ARM && (ARCH_PXA || MACH_VPAC270) + select BLK_DEV_IDEDMA + config BLK_DEV_GAYLE bool "Amiga Gayle IDE interface support" depends on AMIGA diff -urN linux-2.6.24.2/drivers/input/serio/Kconfig linux-2.6.24.2-vpac1/drivers/input/serio/Kconfig --- linux-2.6.24.2/drivers/input/serio/Kconfig 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/input/serio/Kconfig 2008-02-22 13:52:46.000000000 +0100 @@ -88,6 +88,17 @@ To compile this driver as a module, choose M here: the module will be called rpckbd. +config SERIO_VPAC270 + tristate "Voipac PXA270 PS/2 controller" + depends on MACH_VPAC270 + default y + help + Say Y here if you have the Voipac PXA270 board and want to use + an AT keyboard/mouse connected to its PS/2 controller. + + To compile this driver as a module, choose M here: the + module will be called vpac270ps2. + config SERIO_AMBAKMI tristate "AMBA KMI keyboard controller" depends on ARM_AMBA diff -urN linux-2.6.24.2/drivers/input/serio/Makefile linux-2.6.24.2-vpac1/drivers/input/serio/Makefile --- linux-2.6.24.2/drivers/input/serio/Makefile 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/input/serio/Makefile 2008-02-22 13:52:46.000000000 +0100 @@ -10,6 +10,7 @@ obj-$(CONFIG_SERIO_SERPORT) += serport.o obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o +obj-$(CONFIG_SERIO_VPAC270) += vpac270ps2.o obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o diff -urN linux-2.6.24.2/drivers/input/serio/vpac270ps2.c linux-2.6.24.2-vpac1/drivers/input/serio/vpac270ps2.c --- linux-2.6.24.2/drivers/input/serio/vpac270ps2.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/input/serio/vpac270ps2.c 2008-02-22 13:52:46.000000000 +0100 @@ -0,0 +1,384 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define VPAC270_SCL1_GPIO 14 +#define VPAC270_SCL1_IRQ IRQ_GPIO(VPAC270_SCL1_GPIO) +#define VPAC270_SDA1_GPIO 19 + +#define VPAC270_SCL2_GPIO 82 +#define VPAC270_SCL2_IRQ IRQ_GPIO(VPAC270_SCL2_GPIO) +#define VPAC270_SDA2_GPIO 106 + +static int kb_parity; +static int kb_bitcount; +static unsigned char kb_scan; // holds the scan code + +static int ms_parity; +static int ms_bitcount; +static unsigned char ms_scan; // holds the scan code + +static irqreturn_t vpac270kb_interrupt(int irq, void *dev_id) +{ + struct serio *port = dev_id; +//printk("%s:%d\n",__FUNCTION__,__LINE__); + if( kb_bitcount > 0) + { + if(--kb_bitcount > 0) // all bits received + { + // check parity bit + if( kb_bitcount == 1 && (GPLR0 & GPIO_bit(VPAC270_SDA1_GPIO)) ) + kb_parity++; + + // bit 2 to 9 is data + // 10 parity bit, 1 start bit and 11 stop bit are ignored + if(kb_bitcount < 10 && kb_bitcount > 1) + { + kb_scan = (kb_scan >> 1); + // keyboard data is connected to PORT3, bit3 + if(GPLR0 & GPIO_bit(VPAC270_SDA1_GPIO)) + { + kb_parity++; + kb_scan = kb_scan | 0x80; + } + } + } + else + { + GPDR0 |= GPIO_bit(VPAC270_SCL1_GPIO); // inhibit ps/2 device + GPCR0 = GPIO_bit(VPAC270_SCL1_GPIO); + +// printk("%s:%d scan=%x, parity=%d\n",__FUNCTION__,__LINE__,kb_scan,kb_parity); + + kb_bitcount = 11; + + serio_interrupt(port, kb_scan, (kb_parity & 1)? 0 : SERIO_PARITY); + + kb_parity = 0; + + GPDR0 &= ~GPIO_bit(VPAC270_SCL1_GPIO); // enable + } + } + else + { + if( ++kb_bitcount < 0) // all bits received + { + if( kb_bitcount == -2) + kb_scan = ~kb_parity; + + // 8 data bits and parity bit + if( kb_bitcount < -1) + { + // set/reset data line + if( kb_scan & 0x01) + { + kb_parity++; + GPSR0 |= GPIO_bit(VPAC270_SDA1_GPIO); + } + else + GPCR0 |= GPIO_bit(VPAC270_SDA1_GPIO); + kb_scan = (kb_scan >> 1); + } + else + { + // handle stop condition + GPDR0 &= ~GPIO_bit(VPAC270_SDA1_GPIO); + } + } + else + { + // setup rx mode + GPDR0 &= ~GPIO_bit(VPAC270_SDA1_GPIO); + kb_bitcount = 11; + kb_parity = 0; + +// printk("%s:%d tx complete\n",__FUNCTION__,__LINE__); + } + } + return IRQ_HANDLED; +} + +static irqreturn_t vpac270ms_interrupt(int irq, void *dev_id) +{ + struct serio *port = dev_id; +//printk("%s:%d\n",__FUNCTION__,__LINE__); + if( ms_bitcount > 0) + { + if(--ms_bitcount > 0) // all bits received + { + // check parity bit + if( ms_bitcount == 1 && (GPLR3 & GPIO_bit(VPAC270_SDA2_GPIO)) ) + ms_parity++; + + // bit 2 to 9 is data + // 10 parity bit, 1 start bit and 11 stop bit are ignored + if(ms_bitcount < 10 && ms_bitcount > 1) + { + ms_scan = (ms_scan >> 1); + // keyboard data is connected to PORT3, bit3 + if(GPLR3 & GPIO_bit(VPAC270_SDA2_GPIO)) + { + ms_parity++; + ms_scan = ms_scan | 0x80; + } + } + } + else + { + GPDR2 |= GPIO_bit(VPAC270_SCL2_GPIO); // inhibit ps/2 device + GPCR2 = GPIO_bit(VPAC270_SCL2_GPIO); + +// printk("%s:%d scan=%x, parity=%d\n",__FUNCTION__,__LINE__,ms_scan,ms_parity); + + ms_bitcount = 11; + + serio_interrupt(port, ms_scan, (ms_parity & 1)? 0 : SERIO_PARITY); + + ms_parity = 0; + + GPDR2 &= ~GPIO_bit(VPAC270_SCL2_GPIO); // enable + } + } + else + { + if( ++ms_bitcount < 0) // all bits received + { + if( ms_bitcount == -2) + ms_scan = ~ms_parity; + + // 8 data bits and parity bit + if( ms_bitcount < -1) + { + // set/reset data line + if( ms_scan & 0x01) + { + ms_parity++; + GPSR3 |= GPIO_bit(VPAC270_SDA2_GPIO); + } + else + GPCR3 |= GPIO_bit(VPAC270_SDA2_GPIO); + ms_scan = (ms_scan >> 1); + } + else + { + // handle stop condition + GPDR3 &= ~GPIO_bit(VPAC270_SDA2_GPIO); + } + } + else + { + // setup rx mode + GPDR3 &= ~GPIO_bit(VPAC270_SDA2_GPIO); + ms_bitcount = 11; + ms_parity = 0; + +// printk("%s:%d tx complete\n",__FUNCTION__,__LINE__); + } + } + return IRQ_HANDLED; +} + +static int vpac270kb_write(struct serio *port, unsigned char val) +{ +//printk("%s:%d val=%x\n",__FUNCTION__,__LINE__,val); + + // setup clk gpio pin as output and set it to low + GPDR0 |= GPIO_bit(VPAC270_SCL1_GPIO); + GPCR0 = GPIO_bit(VPAC270_SCL1_GPIO); + + // wait min 100us + udelay(120); + + // setup data gpio pin as output and set it to low + GPDR0 |= GPIO_bit(VPAC270_SDA1_GPIO); + GPCR0 = GPIO_bit(VPAC270_SDA1_GPIO); + + // set scan and setup tx mode + kb_parity = 0; + kb_bitcount = -11; + kb_scan = val; + + // setup clk gpio pin as input (clk transitions to high by pullup) + GPDR0 &= ~GPIO_bit(VPAC270_SCL1_GPIO); + + return 0; +} + +static int vpac270ms_write(struct serio *port, unsigned char val) +{ +//printk("%s:%d val=%x\n",__FUNCTION__,__LINE__,val); + + // setup clk gpio pin as output and set it to low + GPDR2 |= GPIO_bit(VPAC270_SCL2_GPIO); + GPCR2 = GPIO_bit(VPAC270_SCL2_GPIO); + + // wait min 100us + udelay(120); + + // setup data gpio pin as output and set it to low + GPDR3 |= GPIO_bit(VPAC270_SDA2_GPIO); + GPCR3 = GPIO_bit(VPAC270_SDA2_GPIO); + + // set scan and setup tx mode + ms_parity = 0; + ms_bitcount = -11; + ms_scan = val; + + // setup clk gpio pin as input (clk transitions to high by pullup) + GPDR2 &= ~GPIO_bit(VPAC270_SCL2_GPIO); + + return 0; +} + +static int vpac270kb_open(struct serio *port) +{ +//printk("%s:%d\n",__FUNCTION__,__LINE__); + pxa_gpio_mode(VPAC270_SCL1_GPIO | GPIO_IN); + pxa_gpio_mode(VPAC270_SDA1_GPIO | GPIO_IN); + + if (request_irq( VPAC270_SCL1_IRQ, vpac270kb_interrupt, + SA_INTERRUPT, "vpac270kb", port)) + { + printk(KERN_WARNING "%s: failed to request IRQ: %d!\n", __FUNCTION__, VPAC270_SCL1_IRQ); + } + + set_irq_type(VPAC270_SCL1_IRQ, IRQT_FALLING); + + kb_parity = 0; + kb_bitcount = 11; + + return 0; +} + +static int vpac270ms_open(struct serio *port) +{ +//printk("%s:%d\n",__FUNCTION__,__LINE__); + pxa_gpio_mode(VPAC270_SCL2_GPIO | GPIO_IN); + pxa_gpio_mode(VPAC270_SDA2_GPIO | GPIO_IN); + + if (request_irq( VPAC270_SCL2_IRQ, vpac270ms_interrupt, + SA_INTERRUPT, "vpac270ms", port)) + { + printk(KERN_WARNING "%s: failed to request IRQ: %d!\n", __FUNCTION__, VPAC270_SCL2_IRQ); + } + + set_irq_type(VPAC270_SCL2_IRQ, IRQT_FALLING); + + ms_parity = 0; + ms_bitcount = 11; + + return 0; +} + +static void vpac270kb_close(struct serio *port) +{ +//printk("%s:%d\n",__FUNCTION__,__LINE__); + free_irq( VPAC270_SCL1_IRQ, port); +} + +static void vpac270ms_close(struct serio *port) +{ +//printk("%s:%d\n",__FUNCTION__,__LINE__); + free_irq( VPAC270_SCL2_IRQ, port); +} + +/* + * Allocate and initialize serio structure for subsequent registration + * with serio core. + */ +static int __devinit vpac270ps2_probe(struct platform_device *dev) +{ + struct serio *serio; +//printk("%s:%d\n",__FUNCTION__,__LINE__); + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!serio) + return -ENOMEM; + + memset(serio, 0, sizeof(struct serio)); + serio->id.type = SERIO_8042; + + if( dev->id == 0) + { + serio->write = vpac270kb_write; + serio->open = vpac270kb_open; + serio->close = vpac270kb_close; + serio->dev.parent = &dev->dev; + strlcpy(serio->name, "Voipac PXA270 PS/2 keyboard port", sizeof(serio->name)); + strlcpy(serio->phys, "vpac270/serio0", sizeof(serio->phys)); + } else { + serio->write = vpac270ms_write; + serio->open = vpac270ms_open; + serio->close = vpac270ms_close; + serio->dev.parent = &dev->dev; + strlcpy(serio->name, "Voipac PXA270 PS/2 mouse port", sizeof(serio->name)); + strlcpy(serio->phys, "vpac270/serio1", sizeof(serio->phys)); + } + + platform_set_drvdata(dev, serio); + serio_register_port(serio); + + return 0; +} + +static int __devexit vpac270ps2_remove(struct platform_device *dev) +{ + struct serio *serio = platform_get_drvdata(dev); + + serio_unregister_port(serio); + + return 0; +} + +static struct platform_driver vpac270ps2_driver = { + .probe = vpac270ps2_probe, + .remove = __devexit_p(vpac270ps2_remove), + .driver = { + .name = "vpac270ps2", + }, +}; + +static int __init vpac270ps2_init(void) +{ + return platform_driver_register(&vpac270ps2_driver); +} + +static void __exit vpac270ps2_exit(void) +{ + platform_driver_unregister(&vpac270ps2_driver); +} + +module_init(vpac270ps2_init); +module_exit(vpac270ps2_exit); + +MODULE_AUTHOR("Voipac Technologies "); +MODULE_DESCRIPTION("Voipac PXA270 PS/2 controller driver"); +MODULE_LICENSE("GPL"); + diff -urN linux-2.6.24.2/drivers/leds/Kconfig linux-2.6.24.2-vpac1/drivers/leds/Kconfig --- linux-2.6.24.2/drivers/leds/Kconfig 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/leds/Kconfig 2008-02-22 13:52:46.000000000 +0100 @@ -18,6 +18,13 @@ comment "LED drivers" +config LEDS_VPAC270 + tristate "LED Support for the Voipac PXA270 baseboard" + depends on LEDS_CLASS && MACH_VPAC270 + help + This option enables support for the LED on Voipac + Technologies PXA270 developement baseboard. + config LEDS_CORGI tristate "LED Support for the Sharp SL-C7x0 series" depends on LEDS_CLASS && PXA_SHARP_C7xx diff -urN linux-2.6.24.2/drivers/leds/leds-vpac270.c linux-2.6.24.2-vpac1/drivers/leds/leds-vpac270.c --- linux-2.6.24.2/drivers/leds/leds-vpac270.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/leds/leds-vpac270.c 2008-02-22 13:52:46.000000000 +0100 @@ -0,0 +1,90 @@ +/* + * LED Triggers Core + * + * Copyright (c) 2006 Voipac Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +//#include + +#define VPAC270_GPIO_LED_ORANGE GPIO15_nCS_1 + +static void vpac270led_set(struct led_classdev *led_cdev, enum led_brightness value) +{ + if (value) + GPSR0 = GPIO_bit(VPAC270_GPIO_LED_ORANGE); + else + GPCR0 = GPIO_bit(VPAC270_GPIO_LED_ORANGE); +} + +static struct led_classdev vpac270_orange_led = { + .name = "vpac270:orange", + .default_trigger = "heartbeat", + .brightness_set = vpac270led_set, +}; + +#ifdef CONFIG_PM +static int vpac270led_suspend(struct platform_device *dev, pm_message_t state) +{ + led_classdev_suspend(&vpac270_orange_led); + return 0; +} + +static int vpac270led_resume(struct platform_device *dev) +{ + led_classdev_resume(&vpac270_orange_led); + return 0; +} +#endif + +static int vpac270led_probe(struct platform_device *pdev) +{ + return led_classdev_register(&pdev->dev, &vpac270_orange_led); +} + +static int vpac270led_remove(struct platform_device *pdev) +{ + led_classdev_unregister(&vpac270_orange_led); + return 0; +} + +static struct platform_driver vpac270led_driver = { + .probe = vpac270led_probe, + .remove = vpac270led_remove, +#ifdef CONFIG_PM + .suspend = vpac270led_suspend, + .resume = vpac270led_resume, +#endif + .driver = { + .name = "vpac270-led", + }, +}; + +static int __init vpac270led_init(void) +{ + return platform_driver_register(&vpac270led_driver); +} + +static void __exit vpac270led_exit(void) +{ + platform_driver_unregister(&vpac270led_driver); +} + +module_init(vpac270led_init); +module_exit(vpac270led_exit); + +MODULE_AUTHOR("Voipac Technologies "); +MODULE_DESCRIPTION("Voipac PXA270 LED driver"); +MODULE_LICENSE("GPL"); diff -urN linux-2.6.24.2/drivers/leds/Makefile linux-2.6.24.2-vpac1/drivers/leds/Makefile --- linux-2.6.24.2/drivers/leds/Makefile 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/leds/Makefile 2008-02-22 13:52:46.000000000 +0100 @@ -5,6 +5,7 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o # LED Platform Drivers +obj-$(CONFIG_LEDS_VPAC270) += leds-vpac270.o obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o diff -urN linux-2.6.24.2/drivers/mtd/maps/Kconfig linux-2.6.24.2-vpac1/drivers/mtd/maps/Kconfig --- linux-2.6.24.2/drivers/mtd/maps/Kconfig 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/mtd/maps/Kconfig 2008-02-22 13:52:46.000000000 +0100 @@ -484,6 +484,13 @@ This enables access to the flash chips on the Hynix evaluation boards. If you have such a board, say 'Y'. +config MTD_VPAC270 + tristate "Voipac PXA270 module flash mapping" + depends on MACH_VPAC270 && MTD_CFI && MTD_PARTITIONS + help + This enables access to the flash memory on the Voipac PXA270 module. + If you have such a module, say 'Y'. + config MTD_MPC1211 tristate "CFI Flash device mapped on Interface MPC-1211" depends on SH_MPC1211 && MTD_CFI diff -urN linux-2.6.24.2/drivers/mtd/maps/Makefile linux-2.6.24.2-vpac1/drivers/mtd/maps/Makefile --- linux-2.6.24.2/drivers/mtd/maps/Makefile 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/mtd/maps/Makefile 2008-02-22 13:52:46.000000000 +0100 @@ -69,3 +69,4 @@ obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o +obj-$(CONFIG_MTD_VPAC270) += vpac270.o diff -urN linux-2.6.24.2/drivers/mtd/maps/vpac270.c linux-2.6.24.2-vpac1/drivers/mtd/maps/vpac270.c --- linux-2.6.24.2/drivers/mtd/maps/vpac270.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/mtd/maps/vpac270.c 2008-02-22 13:52:46.000000000 +0100 @@ -0,0 +1,142 @@ +/* + * Map driver for the Voipac PXA270 module + * + * Modified from drivers/mtd/maps/iq80310.c + * Orignal Author: Nicolas Pitre + * + * Copyright: (C) 2001 MontaVista Software Inc. + * Copyright (c) 2006 Voipac Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define ROM_ADDR 0x00000000 +#define WINDOW_SIZE 32*1024*1024 + +#ifdef CONFIG_PM +struct pm_dev *flash_pmdev; +#endif + +static struct map_info vpac270_map = { + .name = "Voipac PXA270 Flash", + .size = WINDOW_SIZE, + .bankwidth = 2, + .phys = ROM_ADDR +}; + +static struct mtd_partition vpac270_partitions[] = { + { + name: "Bootloader", + size: 0x00020000, /* 128kB u-boot and config params */ + offset: 0, + /*mask_flags: MTD_WRITEABLE force read-only */ + },{ + name: "Kernel", + size: 0x00140000, /* 1MB for kernel */ + offset: 0x00020000, + },{ + name: "Filesystem", /* the rest for filesystem */ + size: MTDPART_SIZ_FULL, + offset: 0x00160000 + } +}; + +static struct mtd_info *mymtd; + +#ifdef VPAC270_PARTS_PARSING +static struct mtd_partition *parsed_parts; +static int nr_parsed_parts; + +static const char* probes[] = { "RedBoot", "cmdlinepart", NULL }; +#endif + +#include + +static int __init init_vpac270(void) +{ + printk( "Probing Voipac PXA270 flash at physical address 0x%08lx (%d-bit buswidth)\n", + vpac270_map.phys, vpac270_map.bankwidth * 8 ); + + vpac270_map.virt = ioremap(vpac270_map.phys, vpac270_map.size); + if (!vpac270_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } + + simple_map_init(&vpac270_map); + + mymtd = do_map_probe("cfi_probe", &vpac270_map); + if (!mymtd) { + iounmap((void *)vpac270_map.virt); + return -ENXIO; + } + mymtd->owner = THIS_MODULE; + +#ifdef DO_FLASH_UNLOCK + /* Unlock the flash device. */ + for (i = 0; i < mymtd->numeraseregions; i++) { + int j; + for( j = 0; j < mymtd->eraseregions[i].numblocks; j++) { + mymtd->unlock(mymtd, mymtd->eraseregions[i].offset + + j * mymtd->eraseregions[i].erasesize, + mymtd->eraseregions[i].erasesize); + } + } +#endif + +#ifdef VPAC270_PARTS_PARSING + ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0); + + if (ret > 0) + nr_parsed_parts = ret; +#endif + + if (!mymtd) { + printk(KERN_WARNING "%s is absent. Skipping\n", vpac270_map.name); +#ifdef VPAC270_PARTS_PARSING + } else if (nr_parsed_parts) { + add_mtd_partitions(mymtd, parsed_parts, nr_parsed_parts); +#endif + } else { + add_mtd_partitions(mymtd, vpac270_partitions, ARRAY_SIZE(vpac270_partitions)); + } + + return 0; +} + +static void __exit cleanup_vpac270(void) +{ + if (mymtd) { +#ifdef VPAC270_PARTS_PARSING + if (nr_parsed_parts) + del_mtd_partitions(mymtd); + else +#endif + del_mtd_device(mymtd); + + map_destroy(mymtd); +#ifdef VPAC270_PARTS_PARSING + if (parsed_parts) + kfree(parsed_parts); +#endif + } + + if (vpac270_map.virt) + iounmap((void *)vpac270_map.virt); +} + +module_init(init_vpac270); +module_exit(cleanup_vpac270); + diff -urN linux-2.6.24.2/drivers/net/dm9000.c linux-2.6.24.2-vpac1/drivers/net/dm9000.c --- linux-2.6.24.2/drivers/net/dm9000.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/net/dm9000.c 2008-02-22 13:52:46.000000000 +0100 @@ -427,9 +427,10 @@ ret = -ENODEV; goto out; } else if (pdev->num_resources == 2) { - base = pdev->resource[0].start; + iosize = 4; + base = (unsigned long) ioremap(pdev->resource[0].start, 8); - if (!request_mem_region(base, 4, ndev->name)) { + if (!request_mem_region(base, 8, ndev->name)) { ret = -EBUSY; goto out; } @@ -437,7 +438,7 @@ ndev->base_addr = base; ndev->irq = pdev->resource[1].start; db->io_addr = (void __iomem *)base; - db->io_data = (void __iomem *)(base + 4); + db->io_data = (void __iomem *)(base + iosize); /* ensure at least we have a default set of IO routines */ dm9000_set_io(db, 2); @@ -494,11 +495,11 @@ ndev->base_addr = (unsigned long)db->io_addr; ndev->irq = db->irq_res->start; - - /* ensure at least we have a default set of IO routines */ - dm9000_set_io(db, iosize); } + /* ensure at least we have a default set of IO routines */ + dm9000_set_io(db, iosize); + /* check to see if anything is being over-ridden */ if (pdata != NULL) { /* check to see if the driver wants to over-ride the diff -urN linux-2.6.24.2/drivers/net/wireless/hostap/hostap_cs.c linux-2.6.24.2-vpac1/drivers/net/wireless/hostap/hostap_cs.c --- linux-2.6.24.2/drivers/net/wireless/hostap/hostap_cs.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/net/wireless/hostap/hostap_cs.c 2008-02-22 13:52:46.000000000 +0100 @@ -31,7 +31,7 @@ MODULE_LICENSE("GPL"); -static int ignore_cis_vcc; +static int ignore_cis_vcc = 1; module_param(ignore_cis_vcc, int, 0444); MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry"); @@ -822,6 +822,7 @@ PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), + PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301), PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b), @@ -834,7 +835,9 @@ PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0004), PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0007), PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002), PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF", diff -urN linux-2.6.24.2/drivers/pcmcia/Makefile linux-2.6.24.2-vpac1/drivers/pcmcia/Makefile --- linux-2.6.24.2/drivers/pcmcia/Makefile 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/pcmcia/Makefile 2008-02-22 13:52:46.000000000 +0100 @@ -71,4 +71,5 @@ pxa2xx_cs-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o pxa2xx_cs-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o pxa2xx_cs-$(CONFIG_MACH_ARMCORE) += pxa2xx_cm_x270.o +pxa2xx_cs-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o diff -urN linux-2.6.24.2/drivers/pcmcia/pxa2xx_vpac270.c linux-2.6.24.2-vpac1/drivers/pcmcia/pxa2xx_vpac270.c --- linux-2.6.24.2/drivers/pcmcia/pxa2xx_vpac270.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/pcmcia/pxa2xx_vpac270.c 2008-02-22 13:52:46.000000000 +0100 @@ -0,0 +1,246 @@ +/* + * linux26/drivers/pcmcia/pxa2xx_vpac270.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Copyright (c) 2002 Accelent Systems, Inc. All Rights Reserved + * Copyright (c) 2006 Voipac Technologies + * + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "soc_common.h" + +//#define DEBUG_COL_PCMCIA + +#ifdef DEBUG_COL_PCMCIA +#define MARK printk(KERN_INFO "%s: %d\n", __FUNCTION__, __LINE__); +#else +//#define MARK (0) +#endif +#ifdef PCMCIA_DEBUG +int pc_debug = PCMCIA_DEBUG; +#endif + +static struct pcmcia_irqs irqs[] = { + { 0, VPAC270_PCMCIA0_CD_IRQ, "CF CD"}, + { 1, VPAC270_PCMCIA1_CD_IRQ, "PCMCIA CD"}, +}; + + +static int vpac270_pcmcia_init_dev(struct soc_pcmcia_socket *skt) +{ + printk("Voipac PXA270 PCMCIA\n"); + /* set power GPIO; switch off */ + GPCR(GPIO_PCMCIA_POW_EN) |= GPIO_bit(GPIO_PCMCIA_POW_EN); + GPDR(GPIO_PCMCIA_POW_EN) |= GPIO_bit(GPIO_PCMCIA_POW_EN); + + /* set PCMCIA AFs */ + GPSR(GPIO_PCMCIA_NPOE) |= GPIO_bit(GPIO_PCMCIA_NPOE); + pxa_gpio_mode(GPIO_PCMCIA_NPOE | GPIO_PCMCIA_NPOE_AF); + + GPSR(GPIO_PCMCIA_NPIOR) |= GPIO_bit(GPIO_PCMCIA_NPIOR); + pxa_gpio_mode(GPIO_PCMCIA_NPIOR | GPIO_PCMCIA_NPIOR_AF); + + GPSR(GPIO_PCMCIA_NPIOW) |= GPIO_bit(GPIO_PCMCIA_NPIOW); + pxa_gpio_mode(GPIO_PCMCIA_NPIOW | GPIO_PCMCIA_NPIOW_AF); + + GPSR(GPIO_PCMCIA_NPCE1) |= GPIO_bit(GPIO_PCMCIA_NPCE1); + pxa_gpio_mode(GPIO_PCMCIA_NPCE1 | GPIO_PCMCIA_NPCE1_AF); + + GPCR(GPIO_PCMCIA_NPCE2) |= GPIO_bit(GPIO_PCMCIA_NPCE2); + pxa_gpio_mode(GPIO_PCMCIA_NPCE2 | GPIO_PCMCIA_NPCE2_AF); + + GPSR(GPIO_PCMCIA_NPREG) |= GPIO_bit(GPIO_PCMCIA_NPREG); + pxa_gpio_mode(GPIO_PCMCIA_NPREG | GPIO_PCMCIA_NPREG_AF); + + pxa_gpio_mode(GPIO_PCMCIA_NPWAIT | GPIO_PCMCIA_NPWAIT_AF); + + pxa_gpio_mode(GPIO_PCMCIA_NPIOIS16 | GPIO_PCMCIA_NPIOIS16_AF); + + GPSR(GPIO_PCMCIA_PSKTSEL) |= GPIO_bit(GPIO_PCMCIA_PSKTSEL); + pxa_gpio_mode(GPIO_PCMCIA_PSKTSEL | GPIO_PCMCIA_PSKTSEL_AF); + + /* set other PCMCIA GPIOs */ + GPCR(GPIO_PCMCIA0_RESET) |= GPIO_bit(GPIO_PCMCIA0_RESET); + GPDR(GPIO_PCMCIA0_RESET) |= GPIO_bit(GPIO_PCMCIA0_RESET); + GPCR(GPIO_PCMCIA1_RESET) |= GPIO_bit(GPIO_PCMCIA1_RESET); + GPDR(GPIO_PCMCIA1_RESET) |= GPIO_bit(GPIO_PCMCIA1_RESET); + +// GPDR(GPIO_PCMCIA0_BVD1) &= ~GPIO_bit(GPIO_PCMCIA0_BVD1); +// GPDR(GPIO_PCMCIA0_BVD2) &= ~GPIO_bit(GPIO_PCMCIA0_BVD2); + + /* switch power on */ + PCC_PWR_ON(); + + /* set interrupts */ + GPDR(GPIO_PCMCIA0_CD_IRQ) &= ~GPIO_bit(GPIO_PCMCIA0_CD_IRQ); + set_irq_type(GPIO_PCMCIA0_CD_IRQ, VPAC270_PCMCIA_CD_EDGE); + + GPDR(GPIO_PCMCIA0_RDY_IRQ) &= ~GPIO_bit(GPIO_PCMCIA0_RDY_IRQ); + set_irq_type(GPIO_PCMCIA0_RDY_IRQ, VPAC270_PCMCIA_RDY_EDGE); + + GPDR(GPIO_PCMCIA1_CD_IRQ) &= ~GPIO_bit(GPIO_PCMCIA1_CD_IRQ); + set_irq_type(GPIO_PCMCIA1_CD_IRQ, VPAC270_PCMCIA_CD_EDGE); + + GPDR(GPIO_PCMCIA1_RDY_IRQ) &= ~GPIO_bit(GPIO_PCMCIA1_RDY_IRQ); + set_irq_type(GPIO_PCMCIA1_RDY_IRQ, VPAC270_PCMCIA_RDY_EDGE); + + if (skt->irq == NO_IRQ) + skt->irq = skt->nr ? VPAC270_PCMCIA1_RDY_IRQ : VPAC270_PCMCIA0_RDY_IRQ; + + return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); +} + +static void vpac270_pcmcia_shutdown(struct soc_pcmcia_socket *skt) +{ + soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); + + /* switch power off */ + PCC_PWR_OFF(); +} + +static void vpac270_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + //memset(state, 0, sizeof(*state)); + + switch( skt->nr) + { + case 0: + state->detect = (PCC0_DETECT) ? 0 : 1; + state->ready = (PCC0_READY) ? 1 : 0; + break; + + case 1: + state->detect = (PCC1_DETECT) ? 0 : 1; + state->ready = (PCC1_READY) ? 1 : 0; + break; + + default: + return; + } +/* + printk(KERN_INFO "CF status: detect: %u, ready: %u\n", + GPLR(84) & GPIO_bit(84), + GPLR(1) & GPIO_bit(1)); +*/ + + state->bvd1 = 1; //PCC_BVD1() ? 1 : 0; + state->bvd2 = 1; //PCC_BVD2() ? 1 : 0; + state->wrprot = 0; /* r/w all the time */ + state->vs_3v = PCC_VS3V() ? 1 : 0; + state->vs_Xv = PCC_VS5V() ? 1 : 0; +} + +static int vpac270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + socket_state_t const *state) +{ + unsigned long flags; + + local_irq_save(flags); + /* configure Vcc and Vpp */ + if (state->Vcc == 0 && state->Vpp == 0) + { + PCC_PWR_OFF(); + } + else if (state->Vcc == 33 && state->Vpp < 50) + { + PCC_PWR_ON(); + } + else + { + printk(KERN_ERR "%s(): unsupported Vcc %u Vpp %u combination\n", + __FUNCTION__, state->Vcc, state->Vpp); + return -1; + } + + /* reset PCMCIA if requested */ + if (state->flags & SS_RESET) + { + if( skt->nr == 0) + GPSR(GPIO_PCMCIA0_RESET) |= GPIO_bit(GPIO_PCMCIA0_RESET); + else + GPSR(GPIO_PCMCIA1_RESET) |= GPIO_bit(GPIO_PCMCIA1_RESET); + } else { + if( skt->nr == 0) + GPCR(GPIO_PCMCIA0_RESET) |= GPIO_bit(GPIO_PCMCIA0_RESET); + else + GPCR(GPIO_PCMCIA1_RESET) |= GPIO_bit(GPIO_PCMCIA1_RESET); + } + + local_irq_restore(flags); + udelay(200); + + return 0; +} + +static void vpac270_pcmcia_socket_init(struct soc_pcmcia_socket *skt) +{ +} + +static void vpac270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) +{ +} + +struct pcmcia_low_level vpac270_pcmcia_ops = { + .owner = THIS_MODULE, + .hw_init = vpac270_pcmcia_init_dev, + .hw_shutdown = vpac270_pcmcia_shutdown, + .socket_state = vpac270_pcmcia_socket_state, + .configure_socket = vpac270_pcmcia_configure_socket, + .socket_init = vpac270_pcmcia_socket_init, + .socket_suspend = vpac270_pcmcia_socket_suspend, + .first = 0, + .nr = 2 +}; + +static struct platform_device *vpac270_pcmcia_device; + +static int __init vpac270_pcmcia_init(void) +{ + int ret; + + vpac270_pcmcia_device = kmalloc(sizeof(*vpac270_pcmcia_device), GFP_KERNEL); + if (!vpac270_pcmcia_device) + return -ENOMEM; + memset(vpac270_pcmcia_device, 0, sizeof(*vpac270_pcmcia_device)); + vpac270_pcmcia_device->name = "pxa2xx-pcmcia"; + vpac270_pcmcia_device->dev.platform_data = &vpac270_pcmcia_ops; + + ret = platform_device_register(vpac270_pcmcia_device); + if (ret) + kfree(vpac270_pcmcia_device); + + return ret; +} + +static void __exit vpac270_pcmcia_exit(void) +{ + /* Are there still references to vpac270_pcmcia_device? + * I don't know, so I'd better not free it. + * Actually, I don't really care, as I don't really support + * this driver as module anyway... + */ + platform_device_unregister(vpac270_pcmcia_device); +} + +module_init(vpac270_pcmcia_init); +module_exit(vpac270_pcmcia_exit); + +MODULE_DESCRIPTION("Voipac PXA270 CF Support"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Voipac Technologies "); diff -urN linux-2.6.24.2/drivers/usb/gadget/char.c linux-2.6.24.2-vpac1/drivers/usb/gadget/char.c --- linux-2.6.24.2/drivers/usb/gadget/char.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/char.c 2008-02-22 13:52:46.000000000 +0100 @@ -0,0 +1,911 @@ +/* + * char.c -- Character Gadget + * + * Copyright (C) 2003-2005 Joshua Wise. + * Portions copyright (C) 2003-2004 David Brownell. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define DEBUG 1 +#define VERBOSE +#define DBUFMAX 8192 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +struct gchar_dev { + spinlock_t lock; + struct usb_gadget *gadget; + struct usb_request *req; /* for control responses */ + struct usb_ep *in_ep, *out_ep; + + int configured; + + unsigned char databuf[DBUFMAX]; + int databuflen; + spinlock_t buflock; + wait_queue_head_t wait; +}; + +/*-------------------------------------------------------------------------*/ + +static int gchar_bind_misc(struct gchar_dev *dev); +static int gchar_unbind_misc(struct gchar_dev *dev); + +/*-------------------------------------------------------------------------*/ + +static const char shortname [] = "char"; +static const char longname [] = "Character Gadget"; + +static const char charmode [] = "Character mode"; + +/*-------------------------------------------------------------------------*/ + +#define EP0_MAXPACKET 16 +static const char *EP_OUT_NAME; +static const char *EP_IN_NAME; + +/*-------------------------------------------------------------------------*/ + +/* any hub supports this steady state bus power consumption */ +#define MAX_USB_POWER 100 /* mA */ + +/* big enough to hold our biggest descriptor */ +#define USB_BUFSIZ 256 + +/*-------------------------------------------------------------------------*/ + +#define xprintk(d,level,fmt,args...) dev_printk(level , &(d)->gadget->dev , fmt , ## args) + +#ifdef DEBUG +# undef DEBUG +# define DEBUG(dev,fmt,args...) printk(KERN_DEBUG "gchar: " fmt , ## args) +#else +# define DEBUG(dev,fmt,args...) do { } while (0) +#endif /* DEBUG */ + +#ifdef VERBOSE +# define VDEBUG DEBUG +#else +# define VDEBUG(dev,fmt,args...) do { } while (0) +#endif /* VERBOSE */ + +#define ERROR(dev,fmt,args...) printk(KERN_ERR "gchar: " fmt , ## args) +#define WARN(dev,fmt,args...) printk(KERN_WARNING "gchar: " fmt , ## args) +#define INFO(dev,fmt,args...) printk(KERN_INFO "gchar: " fmt , ## args) + +/*-------------------------------------------------------------------------*/ + +static unsigned buflen = 1536; +static unsigned qlen = 4; + +module_param (buflen, uint, S_IRUGO|S_IWUSR); +module_param (qlen, uint, S_IRUGO|S_IWUSR); + +/*-------------------------------------------------------------------------*/ + +#define DRIVER_VENDOR_NUM 0x6666 /* Experimental */ +#define DRIVER_PRODUCT_NUM 0xB007 /* Bootloader */ + +/*-------------------------------------------------------------------------*/ + +/* + * DESCRIPTORS ... most are static, but strings and (full) + * configuration descriptors are built on demand. + */ + +#define STRING_MANUFACTURER 25 +#define STRING_PRODUCT 42 +#define STRING_SERIAL 101 +#define STRING_CHAR 250 + +/* + * This device advertises one configuration. + */ +#define CONFIG_CHAR 1 + +static struct usb_device_descriptor +device_desc = { + .bLength = sizeof device_desc, + .bDescriptorType = USB_DT_DEVICE, + + .bcdUSB = __constant_cpu_to_le16 (0x0200), + .bDeviceClass = USB_CLASS_VENDOR_SPEC, + + .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM), + .bcdDevice = __constant_cpu_to_le16 (0x0000), + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .iSerialNumber = STRING_SERIAL, + .bNumConfigurations = 1, +}; + +static const struct usb_config_descriptor +char_config = { + .bLength = sizeof char_config, + .bDescriptorType = USB_DT_CONFIG, + + /* compute wTotalLength on the fly */ + .bNumInterfaces = 1, + .bConfigurationValue = CONFIG_CHAR, + .iConfiguration = STRING_CHAR, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER | 0 /* no wakeup support */, + .bMaxPower = (MAX_USB_POWER + 1) / 2, +}; + +/* one interface in each configuration */ + +static const struct usb_interface_descriptor +char_intf = { + .bLength = sizeof char_intf, + .bDescriptorType = USB_DT_INTERFACE, + + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .iInterface = STRING_CHAR, +}; + +/* two full speed bulk endpoints; their use is config-dependent */ + +static struct usb_endpoint_descriptor +fs_char_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_endpoint_descriptor +fs_char_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +/* if there's no high speed support, maxpacket doesn't change. */ +static char manufacturer [50]; +static char serial [40]; + +/* static strings, in iso 8859/1 */ +static struct usb_string strings [] = { + { STRING_MANUFACTURER, manufacturer, }, + { STRING_PRODUCT, longname, }, + { STRING_SERIAL, serial, }, + { STRING_CHAR, charmode, }, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab = { + .language = 0x0409, /* en-us */ + .strings = strings, +}; + +static int +config_buf (enum usb_device_speed speed, + u8 *buf, u8 type, unsigned index) +{ + const unsigned config_len = USB_DT_CONFIG_SIZE + + USB_DT_INTERFACE_SIZE + + 2 * USB_DT_ENDPOINT_SIZE; + + /* two configurations will always be index 0 and index 1 */ + if (index > 1) + return -EINVAL; + if (config_len > USB_BUFSIZ) + return -EDOM; + + /* config (or other speed config) */ + memcpy (buf, &char_config, USB_DT_CONFIG_SIZE); + buf [1] = type; + ((struct usb_config_descriptor *) buf)->wTotalLength + = __constant_cpu_to_le16 (config_len); + buf += USB_DT_CONFIG_SIZE; + + /* one interface */ + memcpy (buf, &char_intf, USB_DT_INTERFACE_SIZE); + buf += USB_DT_INTERFACE_SIZE; + + /* the endpoints in that interface (at that speed) */ + memcpy (buf, &fs_char_in_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + memcpy (buf, &fs_char_out_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + + return config_len; +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_request * +alloc_ep_req (struct usb_ep *ep, unsigned length) +{ + struct usb_request *req; + + req = usb_ep_alloc_request (ep, GFP_ATOMIC); + if (req) { + req->length = length; + req->buf = usb_ep_alloc_buffer (ep, length, + &req->dma, GFP_ATOMIC); + if (!req->buf) { + usb_ep_free_request (ep, req); + req = NULL; + } + } + return req; +} + +static void free_ep_req (struct usb_ep *ep, struct usb_request *req) +{ + if (req->buf) + usb_ep_free_buffer (ep, req->buf, req->dma, req->length); + usb_ep_free_request (ep, req); +} + +/*-------------------------------------------------------------------------*/ + +static void gchar_complete (struct usb_ep *ep, struct usb_request *req) +{ + struct gchar_dev *dev = ep->driver_data; + int status = req->status; + + switch (status) { + + case 0: /* normal completion? */ + if (ep != dev->out_ep) { + ERROR (dev, "complete: invalid endpoint --> %s (%d/%d)\n", ep->name, req->actual, req->length); + free_ep_req (ep, req); + return; + } + + /* it looks like you've got a packet! */ + req->length = req->actual; + + spin_lock(&dev->buflock); + { + int cpylen; + + cpylen = ((dev->databuflen+req->actual) < DBUFMAX) ? req->actual : (DBUFMAX - dev->databuflen); + memcpy(&dev->databuf[dev->databuflen], req->buf, cpylen); + dev->databuflen += cpylen; + } + spin_unlock(&dev->buflock); + wake_up_interruptible(&dev->wait); + + /* queue the buffer for some later OUT packet */ + req->length = buflen; + status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC); + if (status == 0) + return; + + /* FALLTHROUGH */ + default: + ERROR (dev, "%s gchar recv complete --> %d, %d/%d\n", ep->name, + status, req->actual, req->length); + /* FALLTHROUGH */ + + /* NOTE: since this driver doesn't maintain an explicit record + * of requests it submitted (just maintains qlen count), we + * rely on the hardware driver to clean up on disconnect or + * endpoint disable. + */ + case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNRESET: /* request dequeued */ + case -ESHUTDOWN: /* disconnect from host */ + + return; + } +} + +static int +set_char_config (struct gchar_dev *dev, int gfp_flags) +{ + int result = 0; + struct usb_ep *ep; + struct usb_gadget *gadget = dev->gadget; + + gadget_for_each_ep (ep, gadget) { + /* one endpoint writes data back IN to the host */ + if (strcmp (ep->name, EP_IN_NAME) == 0) { + result = usb_ep_enable (ep, &fs_char_in_desc); + if (result == 0) { + ep->driver_data = dev; + dev->in_ep = ep; + continue; + } + + /* one endpoint just reads OUT packets */ + } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { + result = usb_ep_enable (ep, &fs_char_out_desc); + if (result == 0) { + ep->driver_data = dev; + dev->out_ep = ep; + continue; + } + + /* ignore any other endpoints */ + } else + continue; + + /* stop on error */ + ERROR (dev, "can't enable %s, result %d\n", ep->name, result); + break; + } + + /* allocate a bunch of read buffers and queue them all at once. + * we buffer at most 'qlen' transfers; fewer if any need more + * than 'buflen' bytes each. + */ + if (result == 0) { + struct usb_request *req; + unsigned i; + + ep = dev->out_ep; + for (i = 0; i < qlen && result == 0; i++) { + DEBUG (dev, "%s alloc req of size %d (%d/%d)\n", ep->name, buflen, i, qlen); + req = alloc_ep_req (ep, buflen); + if (req) { + req->complete = gchar_complete; + result = usb_ep_queue (ep, req, GFP_ATOMIC); + if (result) + DEBUG (dev, "%s queue req --> %d\n", + ep->name, result); + } else + result = -ENOMEM; + } + + } + + /* caller is responsible for cleanup on error */ + return result; +} + +/*-------------------------------------------------------------------------*/ + +static void gchar_reset_config (struct gchar_dev *dev) +{ + if (dev->configured == 0) + return; + + DEBUG (dev, "reset config\n"); + + /* just disable endpoints, forcing completion of pending i/o. + * all our completion handlers free their requests in this case. + */ + if (dev->in_ep) { + usb_ep_disable (dev->in_ep); + dev->in_ep = NULL; + } + if (dev->out_ep) { + usb_ep_disable (dev->out_ep); + dev->out_ep = NULL; + } + dev->configured = 0; +} + +/* change our operational config. this code must agree with the code + * that returns config descriptors, and altsetting code. + * + * it's also responsible for power management interactions. some + * configurations might not work with our current power sources. + * + * note that some device controller hardware will constrain what this + * code can do, perhaps by disallowing more than one configuration or + * by limiting configuration choices (like the pxa2xx). + */ +static int +gchar_set_config (struct gchar_dev *dev, unsigned number, int gfp_flags) +{ + int result = 0; + struct usb_gadget *gadget = dev->gadget; + +#if 0 + if (dev->configured) + return 0; +#endif + +#ifdef CONFIG_USB_CHAR_SA1100 + if (dev->configured) { + /* tx fifo is full, but we can't clear it...*/ + INFO (dev, "can't change configurations\n"); + return -ESPIPE; + } +#endif + gchar_reset_config (dev); + + switch (number) { + case CONFIG_CHAR: + result = set_char_config (dev, gfp_flags); + break; + default: + result = -EINVAL; + /* FALL THROUGH */ + case 0: + return result; + } + + if (!result && (!dev->in_ep || !dev->out_ep)) + result = -ENODEV; + if (result) + gchar_reset_config (dev); + else { + char *speed; + + switch (gadget->speed) { + case USB_SPEED_LOW: speed = "low"; break; + case USB_SPEED_FULL: speed = "full"; break; + case USB_SPEED_HIGH: speed = "high"; break; + default: speed = "?"; break; + } + + dev->configured = 1; + INFO (dev, "%s speed\n", speed); + } + return result; +} + +/*-------------------------------------------------------------------------*/ + +static void gchar_setup_complete (struct usb_ep *ep, struct usb_request *req) +{ + if (req->status || req->actual != req->length) + DEBUG ((struct gchar_dev *) ep->driver_data, + "setup complete --> %d, %d/%d\n", + req->status, req->actual, req->length); +} + +/* + * The setup() callback implements all the ep0 functionality that's + * not handled lower down, in hardware or the hardware driver (like + * device and endpoint feature flags, and their status). It's all + * housekeeping for the gadget function we're implementing. Most of + * the work is in config-specific setup. + */ +static int +gchar_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +{ + struct gchar_dev *dev = get_gadget_data (gadget); + struct usb_request *req = dev->req; + int value = -EOPNOTSUPP; + + /* usually this stores reply data in the pre-allocated ep0 buffer, + * but config change events will reconfigure hardware. + */ + switch (ctrl->bRequest) { + + case USB_REQ_GET_DESCRIPTOR: + if (ctrl->bRequestType != USB_DIR_IN) + break; + switch (ctrl->wValue >> 8) { + + case USB_DT_DEVICE: + value = min (ctrl->wLength, (u16) sizeof device_desc); + memcpy (req->buf, &device_desc, value); + break; + case USB_DT_CONFIG: + value = config_buf (gadget->speed, req->buf, + ctrl->wValue >> 8, + ctrl->wValue & 0xff); + if (value >= 0) + value = min (ctrl->wLength, (u16) value); + break; + + case USB_DT_STRING: + /* wIndex == language code. + * this driver only handles one language, you can + * add others even if they don't use iso8859/1 + */ + value = usb_gadget_get_string (&stringtab, + ctrl->wValue & 0xff, req->buf); + if (value >= 0) + value = min (ctrl->wLength, (u16) value); + break; + } + break; + + /* currently two configs, two speeds */ + case USB_REQ_SET_CONFIGURATION: + if (ctrl->bRequestType != 0) + break; + spin_lock (&dev->lock); + value = gchar_set_config (dev, ctrl->wValue, GFP_ATOMIC); + spin_unlock (&dev->lock); + break; + case USB_REQ_GET_CONFIGURATION: + if (ctrl->bRequestType != USB_DIR_IN) + break; + *(u8 *)req->buf = dev->configured ? CONFIG_CHAR : 0; + value = min (ctrl->wLength, (u16) 1); + break; + case USB_REQ_SET_INTERFACE: + if (ctrl->bRequestType != USB_RECIP_INTERFACE) + break; + spin_lock (&dev->lock); + if (dev->configured && ctrl->wIndex == 0 && ctrl->wValue == 0) { + u8 config = dev->configured ? CONFIG_CHAR : 0; + + gchar_reset_config (dev); + gchar_set_config (dev, config, GFP_ATOMIC); + value = 0; + } + spin_unlock (&dev->lock); + break; + case USB_REQ_GET_INTERFACE: + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) + break; + if (!dev->configured) + break; + if (ctrl->wIndex != 0) { + value = -EDOM; + break; + } + *(u8 *)req->buf = 0; + value = min (ctrl->wLength, (u16) 1); + break; + + default: + VDEBUG (dev, + "unknown control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + ctrl->wValue, ctrl->wIndex, ctrl->wLength); + } + + /* respond with data transfer before status phase? */ + if (value >= 0) { + req->length = value; + value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + DEBUG (dev, "ep_queue --> %d\n", value); + req->status = 0; + gchar_setup_complete (gadget->ep0, req); + } + } + + /* device either stalls (value < 0) or reports success */ + return value; +} + +static void +gchar_disconnect (struct usb_gadget *gadget) +{ + struct gchar_dev *dev = get_gadget_data (gadget); + unsigned long flags; + + spin_lock_irqsave (&dev->lock, flags); + gchar_reset_config (dev); + + /* a more significant application might have some non-usb + * activities to quiesce here, saving resources like power + * or pushing the notification up a network stack. + */ + spin_unlock_irqrestore (&dev->lock, flags); + + /* next we may get setup() calls to enumerate new connections; + * or an unbind() during shutdown (including removing module). + */ +} + +/*-------------------------------------------------------------------------*/ + +static void +gchar_unbind (struct usb_gadget *gadget) +{ + struct gchar_dev *dev = get_gadget_data (gadget); + + DEBUG (dev, "unbind\n"); + + /* we've already been disconnected ... no i/o is active */ + if (dev->req) + free_ep_req (gadget->ep0, dev->req); + kfree (dev); + set_gadget_data (gadget, NULL); + + gchar_unbind_misc(dev); + +} + +static int +gchar_bind (struct usb_gadget *gadget) +{ + struct gchar_dev *dev; + struct usb_ep *ep; + int err; + + usb_ep_autoconfig_reset (gadget); + + ep = usb_ep_autoconfig (gadget, &fs_char_in_desc); + if (!ep) { +autoconf_fail: + printk(KERN_ERR "%s: can't autoconfigure on %s\n", shortname, gadget->name); + return -ENODEV; + } + EP_IN_NAME = ep->name; + ep->driver_data = ep; /* claim */ + + ep = usb_ep_autoconfig (gadget, &fs_char_out_desc); + if (!ep) + goto autoconf_fail; + EP_OUT_NAME = ep->name; + ep->driver_data = ep; /* claim */ + + dev = kmalloc (sizeof *dev, SLAB_KERNEL); + if (!dev) + return -ENOMEM; + + memset (dev, 0, sizeof *dev); + spin_lock_init (&dev->lock); + spin_lock_init (&dev->buflock); + dev->gadget = gadget; + init_waitqueue_head (&dev->wait); + + set_gadget_data (gadget, dev); + + /* preallocate control response and buffer */ + dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); + if (!dev->req) + goto enomem; + dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ, + &dev->req->dma, GFP_KERNEL); + if (!dev->req->buf) + goto enomem; + + dev->req->complete = gchar_setup_complete; + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + gadget->ep0->driver_data = dev; + + snprintf (manufacturer, sizeof manufacturer, "%s %s with %s", + system_utsname.sysname, system_utsname.release, + gadget->name); + + /* grab a misc device */ + if ((err = gchar_bind_misc(dev))) { + gchar_unbind(gadget); + return err; + } + + return 0; + +enomem: + gchar_unbind (gadget); + return -ENOMEM; +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_gadget_driver gchar_driver = { + .speed = USB_SPEED_FULL, + .function = (char *) longname, + .bind = gchar_bind, + .unbind = gchar_unbind, + + .setup = gchar_setup, + .disconnect = gchar_disconnect, + + .driver = { + .name = (char *) shortname, + // .shutdown = ... + // .suspend = ... + // .resume = ... + }, +}; + +MODULE_AUTHOR ("Joshua Wise/David Brownell"); +MODULE_LICENSE ("Dual BSD/GPL"); + +static ssize_t read_gchar(struct file* file, char __user *buf, size_t count, loff_t *ppos) +{ + struct gchar_dev *dev = (struct gchar_dev *)file->private_data; + ssize_t readcnt; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&dev->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + do { + if (dev->databuflen != 0) + break; + + if (file->f_flags & O_NONBLOCK) + { + readcnt = -EAGAIN; + goto out; + } + + schedule(); + if (signal_pending(current)) + { + readcnt = -ERESTARTSYS; + goto out; + } + } while (1); + + spin_lock_irq(&dev->buflock); + readcnt = (count > dev->databuflen) ? dev->databuflen : count; + copy_to_user(buf, dev->databuf, readcnt); + memmove(dev->databuf, dev->databuf+readcnt, dev->databuflen-readcnt); + dev->databuflen -= readcnt; + spin_unlock_irq(&dev->buflock); + +out: + current->state = TASK_RUNNING; + remove_wait_queue(&dev->wait, &wait); + + return readcnt; +} + +static void gchar_send_complete (struct usb_ep *ep, struct usb_request *req) +{ + free_ep_req(ep, req); +} + +/*-------------------------------------------------------------------------*/ + +#define USBC_MINOR 240 +#define USBC_MAX_DEVICES 1 + +static ssize_t write_gchar(struct file* file, const char __user *buf, size_t count, loff_t* ppos) +{ + struct gchar_dev *dev = (struct gchar_dev *)file->private_data; + struct usb_request *req; + int result; + + if (!dev->configured) + return count; + + req = alloc_ep_req (dev->in_ep, count); + if (!req) + return -ENOMEM; + + req->complete = gchar_send_complete; + req->length = req->actual = count; + req->zero = 0; + + copy_from_user(req->buf, buf, count); + + result = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); + if (result) + DEBUG (dev, "%s queue req --> %d\n", + dev->in_ep->name, result); + + return count; +} + +static unsigned int poll_gchar( struct file * filp, poll_table *wait ) +{ + struct gchar_dev *dev = (struct gchar_dev *)filp->private_data; + + poll_wait(filp, &dev->wait, wait); + + if (dev->databuflen) + return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM; + return POLLOUT | POLLWRNORM; +} + +/*-------------------------------------------------------------------------*/ + +struct gchar_dev *gc_devs[USBC_MAX_DEVICES]; + +static int open_gchar(struct inode *inode, struct file *file) +{ + struct gchar_dev *dev = gc_devs[iminor(inode)-USBC_MINOR]; + + if (!dev->configured && !dev->databuflen) + return -ENXIO; + + file->private_data = (void*)dev; + nonseekable_open(inode, file); + + return 0; +} + +static struct file_operations gchar_fops = { + .llseek = no_llseek, + .read = read_gchar, + .write = write_gchar, + .poll = poll_gchar, + .open = open_gchar +}; + +static struct miscdevice gchar_misc_device = { + USBC_MINOR, "usbchar", &gchar_fops +}; + +static int gchar_bind_misc(struct gchar_dev *dev) +{ + int error; + + if ((error = misc_register(&gchar_misc_device))) + { + printk("gchar: Unable to register device 10, %d. Errno: %d\n", USBC_MINOR, error); + return error; + } + + gc_devs[gchar_misc_device.minor-USBC_MINOR] = dev; + return 0; +} + +static int gchar_unbind_misc(struct gchar_dev *dev) +{ + misc_deregister (&gchar_misc_device); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static int __init gchar_init (void) +{ + /* a real value would likely come through some id prom + * or module option. this one takes at least two packets. + */ + strlcpy (serial, "hp iPAQ: Linux As Bootloader ", sizeof serial); + + return usb_gadget_register_driver (&gchar_driver); +} +module_init (gchar_init); + +static void __exit cleanup (void) +{ + usb_gadget_unregister_driver (&gchar_driver); + +} +module_exit (cleanup); diff -urN linux-2.6.24.2/drivers/usb/gadget/config.c linux-2.6.24.2-vpac1/drivers/usb/gadget/config.c --- linux-2.6.24.2/drivers/usb/gadget/config.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/config.c 2008-02-22 13:52:46.000000000 +0100 @@ -25,7 +25,7 @@ #include #include -#include +#include /** @@ -50,7 +50,7 @@ return -EINVAL; /* fill buffer from src[] until null descriptor ptr */ - for (; NULL != *src; src++) { + for (; 0 != *src; src++) { unsigned len = (*src)->bLength; if (len > buflen) diff -urN linux-2.6.24.2/drivers/usb/gadget/dummy_hcd.c linux-2.6.24.2-vpac1/drivers/usb/gadget/dummy_hcd.c --- linux-2.6.24.2/drivers/usb/gadget/dummy_hcd.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/dummy_hcd.c 2008-02-22 13:52:46.000000000 +0100 @@ -34,11 +34,14 @@ * bypassing some hardware (and driver) issues. UML could help too. */ +#define DEBUG + #include #include #include #include #include +#include #include #include #include @@ -46,7 +49,7 @@ #include #include #include -#include +#include #include #include @@ -495,6 +498,38 @@ kfree (req); } +static void * +dummy_alloc_buffer ( + struct usb_ep *_ep, + unsigned bytes, + dma_addr_t *dma, + gfp_t mem_flags +) { + char *retval; + struct dummy_ep *ep; + struct dummy *dum; + + ep = usb_ep_to_dummy_ep (_ep); + dum = ep_to_dummy (ep); + + if (!dum->driver) + return NULL; + retval = kmalloc (bytes, mem_flags); + *dma = (dma_addr_t) retval; + return retval; +} + +static void +dummy_free_buffer ( + struct usb_ep *_ep, + void *buf, + dma_addr_t dma, + unsigned bytes +) { + if (bytes) + kfree (buf); +} + static void fifo_complete (struct usb_ep *ep, struct usb_request *req) { @@ -625,6 +660,10 @@ .alloc_request = dummy_alloc_request, .free_request = dummy_free_request, + .alloc_buffer = dummy_alloc_buffer, + .free_buffer = dummy_free_buffer, + /* map, unmap, ... eventually hook the "generic" dma calls */ + .queue = dummy_queue, .dequeue = dummy_dequeue, @@ -962,13 +1001,13 @@ static int dummy_urb_enqueue ( struct usb_hcd *hcd, + struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { struct dummy *dum; struct urbp *urbp; unsigned long flags; - int rc; if (!urb->transfer_buffer && urb->transfer_buffer_length) return -EINVAL; @@ -980,11 +1019,6 @@ dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); - rc = usb_hcd_link_urb_to_ep(hcd, urb); - if (rc) { - kfree(urbp); - goto done; - } if (!dum->udev) { dum->udev = urb->dev; @@ -1001,35 +1035,36 @@ if (!timer_pending (&dum->timer)) mod_timer (&dum->timer, jiffies + 1); - done: - spin_unlock_irqrestore(&dum->lock, flags); - return rc; + spin_unlock_irqrestore (&dum->lock, flags); + return 0; } -static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) +static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { struct dummy *dum; unsigned long flags; - int rc; /* giveback happens automatically in timer callback, * so make sure the callback happens */ dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); - - rc = usb_hcd_check_unlink_urb(hcd, urb, status); - if (!rc && dum->rh_state != DUMMY_RH_RUNNING && - !list_empty(&dum->urbp_list)) + if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list)) mod_timer (&dum->timer, jiffies); - spin_unlock_irqrestore (&dum->lock, flags); - return rc; + return 0; +} + +static void maybe_set_status (struct urb *urb, int status) +{ + spin_lock (&urb->lock); + if (urb->status == -EINPROGRESS) + urb->status = status; + spin_unlock (&urb->lock); } /* transfer up to a frame's worth; caller must own lock */ static int -transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit, - int *status) +transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit) { struct dummy_request *req; @@ -1092,20 +1127,24 @@ * * partially filling a buffer optionally blocks queue advances * (so completion handlers can clean up the queue) but we don't - * need to emulate such data-in-flight. + * need to emulate such data-in-flight. so we only show part + * of the URB_SHORT_NOT_OK effect: completion status. */ if (is_short) { if (host_len == dev_len) { req->req.status = 0; - *status = 0; + maybe_set_status (urb, 0); } else if (to_host) { req->req.status = 0; if (dev_len > host_len) - *status = -EOVERFLOW; + maybe_set_status (urb, -EOVERFLOW); else - *status = 0; + maybe_set_status (urb, + (urb->transfer_flags + & URB_SHORT_NOT_OK) + ? -EREMOTEIO : 0); } else if (!to_host) { - *status = 0; + maybe_set_status (urb, 0); if (host_len > dev_len) req->req.status = -EOVERFLOW; else @@ -1119,8 +1158,9 @@ req->req.status = 0; if (urb->transfer_buffer_length == urb->actual_length && !(urb->transfer_flags - & URB_ZERO_PACKET)) - *status = 0; + & URB_ZERO_PACKET)) { + maybe_set_status (urb, 0); + } } /* device side completion --> continuable */ @@ -1136,7 +1176,7 @@ } /* host side completion --> terminate */ - if (*status != -EINPROGRESS) + if (urb->status != -EINPROGRESS) break; /* rescan to continue with any other queued i/o */ @@ -1247,12 +1287,12 @@ u8 address; struct dummy_ep *ep = NULL; int type; - int status = -EINPROGRESS; urb = urbp->urb; - if (urb->unlinked) + if (urb->status != -EINPROGRESS) { + /* likely it was just unlinked */ goto return_urb; - else if (dum->rh_state != DUMMY_RH_RUNNING) + } else if (dum->rh_state != DUMMY_RH_RUNNING) continue; type = usb_pipetype (urb->pipe); @@ -1273,7 +1313,7 @@ dev_dbg (dummy_dev(dum), "no ep configured for urb %p\n", urb); - status = -EPROTO; + maybe_set_status (urb, -EPROTO); goto return_urb; } @@ -1288,7 +1328,7 @@ /* NOTE: must not be iso! */ dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n", ep->ep.name, urb); - status = -EPIPE; + maybe_set_status (urb, -EPIPE); goto return_urb; } /* FIXME make sure both ends agree on maxpacket */ @@ -1306,7 +1346,7 @@ w_value = le16_to_cpu(setup.wValue); if (le16_to_cpu(setup.wLength) != urb->transfer_buffer_length) { - status = -EOVERFLOW; + maybe_set_status (urb, -EOVERFLOW); goto return_urb; } @@ -1336,7 +1376,7 @@ if (setup.bRequestType != Dev_Request) break; dum->address = w_value; - status = 0; + maybe_set_status (urb, 0); dev_dbg (udc_dev(dum), "set_address = %d\n", w_value); value = 0; @@ -1363,7 +1403,7 @@ if (value == 0) { dum->devstatus |= (1 << w_value); - status = 0; + maybe_set_status (urb, 0); } } else if (setup.bRequestType == Ep_Request) { @@ -1375,7 +1415,7 @@ } ep2->halted = 1; value = 0; - status = 0; + maybe_set_status (urb, 0); } break; case USB_REQ_CLEAR_FEATURE: @@ -1385,7 +1425,7 @@ dum->devstatus &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); value = 0; - status = 0; + maybe_set_status (urb, 0); break; default: value = -EOPNOTSUPP; @@ -1400,7 +1440,7 @@ } ep2->halted = 0; value = 0; - status = 0; + maybe_set_status (urb, 0); } break; case USB_REQ_GET_STATUS: @@ -1437,7 +1477,7 @@ urb->actual_length = min (2, urb->transfer_buffer_length); value = 0; - status = 0; + maybe_set_status (urb, 0); } break; } @@ -1464,7 +1504,7 @@ dev_dbg (udc_dev(dum), "setup --> %d\n", value); - status = -EPIPE; + maybe_set_status (urb, -EPIPE); urb->actual_length = 0; } @@ -1481,7 +1521,7 @@ * report random errors, to debug drivers. */ limit = max (limit, periodic_bytes (dum, ep)); - status = -ENOSYS; + maybe_set_status (urb, -ENOSYS); break; case PIPE_INTERRUPT: @@ -1495,23 +1535,23 @@ default: treat_control_like_bulk: ep->last_io = jiffies; - total = transfer(dum, urb, ep, limit, &status); + total = transfer (dum, urb, ep, limit); break; } /* incomplete transfer? */ - if (status == -EINPROGRESS) + if (urb->status == -EINPROGRESS) continue; return_urb: + urb->hcpriv = NULL; list_del (&urbp->urbp_list); kfree (urbp); if (ep) ep->already_seen = ep->setup_stage = 0; - usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); spin_unlock (&dum->lock); - usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status); + usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); spin_lock (&dum->lock); goto restart; @@ -1745,7 +1785,8 @@ spin_lock_irq (&dum->lock); if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { - rc = -ESHUTDOWN; + dev_warn (&hcd->self.root_hub->dev, "HC isn't running!\n"); + rc = -ENODEV; } else { dum->rh_state = DUMMY_RH_RUNNING; set_link_state (dum); diff -urN linux-2.6.24.2/drivers/usb/gadget/epautoconf.c linux-2.6.24.2-vpac1/drivers/usb/gadget/epautoconf.c --- linux-2.6.24.2/drivers/usb/gadget/epautoconf.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/epautoconf.c 2008-02-22 13:52:46.000000000 +0100 @@ -28,7 +28,7 @@ #include #include -#include +#include #include "gadget_chips.h" @@ -71,7 +71,7 @@ u16 max; /* endpoint already claimed? */ - if (NULL != ep->driver_data) + if (0 != ep->driver_data) return 0; /* only support ep0 for portable CONTROL traffic */ @@ -132,7 +132,7 @@ * where it's an output parameter representing the full speed limit. * the usb spec fixes high speed bulk maxpacket at 512 bytes. */ - max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize); + max = 0x7ff & le16_to_cpup (&desc->wMaxPacketSize); switch (type) { case USB_ENDPOINT_XFER_INT: /* INT: limit 64 bytes full speed, 1024 high speed */ @@ -230,12 +230,17 @@ */ struct usb_ep * __devinit usb_ep_autoconfig ( struct usb_gadget *gadget, - struct usb_endpoint_descriptor *desc + struct usb_endpoint_descriptor *desc, + struct usb_endpoint_config *epconfig, int numconfigs ) { struct usb_ep *ep; u8 type; + /* Use device specific ep allocation code if provided */ + if (gadget->ops->ep_alloc) + return gadget->ops->ep_alloc(gadget, desc, epconfig, numconfigs); + type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; /* First, apply chip-specific "best usage" knowledge. diff -urN linux-2.6.24.2/drivers/usb/gadget/ether.c linux-2.6.24.2-vpac1/drivers/usb/gadget/ether.c --- linux-2.6.24.2/drivers/usb/gadget/ether.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/ether.c 2008-02-22 13:52:46.000000000 +0100 @@ -19,18 +19,41 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* #define VERBOSE_DEBUG */ +// #define DEBUG 1 +// #define VERBOSE + +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include #include -#include -#include + +#include +#include +#include +#include +#include +#include #include #include -#include +#include + +#include +#include +#include +#include #include "gadget_chips.h" @@ -236,7 +259,8 @@ #endif #ifdef CONFIG_USB_GADGET_PXA27X -#define DEV_CONFIG_CDC +//#define DEV_CONFIG_CDC +#define DEV_CONFIG_SUBSET #endif #ifdef CONFIG_USB_GADGET_S3C2410 @@ -255,13 +279,10 @@ #define DEV_CONFIG_CDC #endif -#ifdef CONFIG_USB_GADGET_ATMEL_USBA +#ifdef CONFIG_USB_GADGET_HUSB2DEV #define DEV_CONFIG_CDC #endif -#ifdef CONFIG_USB_GADGET_FSL_USB2 -#define DEV_CONFIG_CDC -#endif /* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. @@ -270,7 +291,7 @@ #define DEV_CONFIG_SUBSET #endif -#ifdef CONFIG_USB_GADGET_SUPERH +#ifdef CONFIG_USB_GADGET_SH #define DEV_CONFIG_SUBSET #endif @@ -279,14 +300,6 @@ #define DEV_CONFIG_SUBSET #endif -#ifdef CONFIG_USB_GADGET_M66592 -#define DEV_CONFIG_CDC -#endif - -#ifdef CONFIG_USB_GADGET_AMD5536UDC -#define DEV_CONFIG_CDC -#endif - /*-------------------------------------------------------------------------*/ @@ -334,15 +347,15 @@ #define qlen(gadget) \ (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1)) +/* also defer IRQs on highspeed TX */ +#define TX_DELAY qmult + static inline int BITRATE(struct usb_gadget *g) { return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS; } #else /* full speed (low speed doesn't do bulk) */ - -#define qmult 1 - #define DEVSPEED USB_SPEED_FULL #define qlen(gadget) DEFAULT_QLEN @@ -368,7 +381,7 @@ do { } while (0) #endif /* DEBUG */ -#ifdef VERBOSE_DEBUG +#ifdef VERBOSE #define VDEBUG DEBUG #else #define VDEBUG(dev,fmt,args...) \ @@ -808,6 +821,8 @@ }; #endif +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -910,15 +925,18 @@ /* maxpacket and other transfer characteristics vary by speed. */ -static inline struct usb_endpoint_descriptor * -ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, - struct usb_endpoint_descriptor *fs) -{ - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return hs; - return fs; +#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) + +#else + +/* if there's no high speed support, maxpacket doesn't change. */ +#define ep_desc(g,hs,fs) (((void)(g)), (fs)) + +static inline void __init hs_subset_descriptors(void) +{ } +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ /*-------------------------------------------------------------------------*/ @@ -962,19 +980,22 @@ * complications: class descriptors, and an altsetting. */ static int -config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg) +config_buf (enum usb_device_speed speed, + u8 *buf, u8 type, + unsigned index, int is_otg) { int len; const struct usb_config_descriptor *config; const struct usb_descriptor_header **function; - int hs = 0; +#ifdef CONFIG_USB_GADGET_DUALSPEED + int hs = (speed == USB_SPEED_HIGH); - if (gadget_is_dualspeed(g)) { - hs = (g->speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; - } + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; #define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function) +#else +#define which_fn(t) (fs_ ## t ## _function) +#endif if (index >= device_desc.bNumConfigurations) return -EINVAL; @@ -1187,7 +1208,7 @@ if (number) eth_reset_config (dev); usb_gadget_vbus_draw(dev->gadget, - gadget_is_otg(dev->gadget) ? 8 : 100); + dev->gadget->is_otg ? 8 : 100); } else { char *speed; unsigned power; @@ -1320,6 +1341,10 @@ /* done sending after USB_CDC_GET_ENCAPSULATED_RESPONSE */ } +#ifdef CONFIG_USB_GADGET_PXA27X +int write_ep0_zlp(void); +#endif + static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req) { struct eth_dev *dev = ep->driver_data; @@ -1330,6 +1355,10 @@ status = rndis_msg_parser (dev->rndis_config, (u8 *) req->buf); if (status < 0) ERROR(dev, "%s: rndis parse error %d\n", __FUNCTION__, status); + +#ifdef CONFIG_USB_GADGET_PXA27X + write_ep0_zlp(); +#endif spin_unlock(&dev->lock); } @@ -1369,22 +1398,24 @@ value = min (wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget_is_dualspeed(gadget)) + if (!gadget->is_dualspeed) break; value = min (wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget_is_dualspeed(gadget)) + if (!gadget->is_dualspeed) break; // FALLTHROUGH +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - value = config_buf(gadget, req->buf, + value = config_buf (gadget->speed, req->buf, wValue >> 8, wValue & 0xff, - gadget_is_otg(gadget)); + gadget->is_otg); if (value >= 0) value = min (wLength, (u16) value); break; @@ -1553,12 +1584,12 @@ && rndis_control_intf.bInterfaceNumber == wIndex) { u8 *buf; - u32 n; /* return the result */ - buf = rndis_get_next_response(dev->rndis_config, &n); + buf = rndis_get_next_response (dev->rndis_config, + &value); if (buf) { - memcpy(req->buf, buf, n); + memcpy (req->buf, buf, value); req->complete = rndis_response_complete; rndis_free_response(dev->rndis_config, buf); } @@ -1691,8 +1722,7 @@ size += sizeof (struct rndis_packet_msg_type); size -= size % dev->out_ep->maxpacket; - skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags); - if (skb == NULL) { + if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) { DEBUG (dev, "no rx skb\n"); goto enomem; } @@ -1714,8 +1744,7 @@ defer_kevent (dev, WORK_RX_MEMORY); if (retval) { DEBUG (dev, "rx submit --> %d\n", retval); - if (skb) - dev_kfree_skb_any(skb); + dev_kfree_skb_any (skb); spin_lock(&dev->req_lock); list_add (&req->list, &dev->rx_reqs); spin_unlock(&dev->req_lock); @@ -1746,6 +1775,7 @@ break; } + skb->dev = dev->net; skb->protocol = eth_type_trans (skb, dev->net); dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; @@ -1957,20 +1987,8 @@ } spin_lock_irqsave(&dev->req_lock, flags); - /* - * this freelist can be empty if an interrupt triggered disconnect() - * and reconfigured the gadget (shutting down this queue) after the - * network stack decided to xmit but before we got the spinlock. - */ - if (list_empty(&dev->tx_reqs)) { - spin_unlock_irqrestore(&dev->req_lock, flags); - return 1; - } - req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); - - /* temporarily stop TX queue when the freelist empties */ if (list_empty (&dev->tx_reqs)) netif_stop_queue (net); spin_unlock_irqrestore(&dev->req_lock, flags); @@ -2006,11 +2024,12 @@ req->length = length; +#ifdef CONFIG_USB_GADGET_DUALSPEED /* throttle highspeed IRQ rate back slightly */ - if (gadget_is_dualspeed(dev->gadget)) - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) - ? ((atomic_read(&dev->tx_qlen) % qmult) != 0) - : 0; + req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) + ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0) + : 0; +#endif retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); switch (retval) { @@ -2167,7 +2186,8 @@ } if (rndis_active(dev)) { - rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0); + rndis_set_param_medium (dev->rndis_config, + NDIS_MEDIUM_802_3, 0); (void) rndis_signal_disconnect (dev->rndis_config); } @@ -2265,7 +2285,8 @@ struct eth_dev *dev; struct net_device *net; u8 cdc = 1, zlp = 1, rndis = 1; - struct usb_ep *in_ep, *out_ep, *status_ep = NULL; + struct usb_ep *in_ep = NULL , *out_ep = NULL, *status_ep = NULL; + struct usb_endpoint_config ep_config[2]; int status = -ENOMEM; int gcnum; @@ -2364,7 +2385,30 @@ /* all we really need is bulk IN/OUT */ usb_ep_autoconfig_reset (gadget); - in_ep = usb_ep_autoconfig (gadget, &fs_source_desc); + + ep_config[0].config = DEV_CONFIG_VALUE; +#if defined(DEV_CONFIG_CDC) + ep_config[0].interface = data_intf.bInterfaceNumber; + ep_config[0].altinterface = data_intf.bAlternateSetting; +#else /* DEV_CONFIG_SUBSET */ + ep_config[0].interface = subset_data_intf.bInterfaceNumber; + ep_config[0].altinterface = subset_data_intf.bAlternateSetting; +#endif + +#ifdef CONFIG_USB_ETH_RNDIS + ep_config[1].config = DEV_RNDIS_CONFIG_VALUE; +#ifdef CONFIG_USB_GADGET_PXA27X + ep_config[1].interface = 0; +#else + ep_config[1].interface = rndis_data_intf.bInterfaceNumber; +#endif + ep_config[1].altinterface = rndis_data_intf.bAlternateSetting; + + in_ep = usb_ep_autoconfig(gadget, &fs_source_desc, &ep_config[0], 2); +#else + in_ep = usb_ep_autoconfig(gadget, &fs_source_desc, &ep_config[0], 1); +#endif + if (!in_ep) { autoconf_fail: dev_err (&gadget->dev, @@ -2374,7 +2418,12 @@ } in_ep->driver_data = in_ep; /* claim */ - out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc); +#ifdef CONFIG_USB_ETH_RNDIS + out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc, &ep_config[0], 2); +#else + out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc, &ep_config[0], 1); +#endif + if (!out_ep) goto autoconf_fail; out_ep->driver_data = out_ep; /* claim */ @@ -2384,7 +2433,25 @@ * Since some hosts expect one, try to allocate one anyway. */ if (cdc || rndis) { - status_ep = usb_ep_autoconfig (gadget, &fs_status_desc); +#ifdef DEV_CONFIG_CDC + ep_config[0].config = DEV_CONFIG_VALUE; + ep_config[0].interface = control_intf.bInterfaceNumber; + ep_config[0].altinterface = control_intf.bAlternateSetting; +#endif +#ifdef CONFIG_USB_ETH_RNDIS + ep_config[1].config = DEV_RNDIS_CONFIG_VALUE; + ep_config[1].interface = rndis_control_intf.bInterfaceNumber; + ep_config[1].altinterface = rndis_control_intf.bAlternateSetting; +#endif + +#if defined(DEV_CONFIG_CDC) && defined(CONFIG_USB_ETH_RNDIS) + status_ep = usb_ep_autoconfig(gadget, &fs_status_desc, &ep_config[0], 2); +#elif defined(CONFIG_USB_ETH_RNDIS) + status_ep = usb_ep_autoconfig(gadget, &fs_status_desc, &ep_config[1], 1); +#else + status_ep = usb_ep_autoconfig(gadget, &fs_status_desc, &ep_config[0], 1); +#endif + if (status_ep) { status_ep->driver_data = status_ep; /* claim */ } else if (rndis) { @@ -2421,28 +2488,26 @@ if (rndis) device_desc.bNumConfigurations = 2; - if (gadget_is_dualspeed(gadget)) { - if (rndis) - dev_qualifier.bNumConfigurations = 2; - else if (!cdc) - dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; - - /* assumes ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = - fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = - fs_sink_desc.bEndpointAddress; +#ifdef CONFIG_USB_GADGET_DUALSPEED + if (rndis) + dev_qualifier.bNumConfigurations = 2; + else if (!cdc) + dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; + + /* assumes ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (status_ep) - hs_status_desc.bEndpointAddress = - fs_status_desc.bEndpointAddress; + if (status_ep) + hs_status_desc.bEndpointAddress = + fs_status_desc.bEndpointAddress; #endif - } +#endif /* DUALSPEED */ - if (gadget_is_otg(gadget)) { + if (gadget->is_otg) { otg_descriptor.bmAttributes |= USB_OTG_HNP, eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; eth_config.bMaxPower = 4; @@ -2464,6 +2529,7 @@ /* network device setup */ dev->net = net; +// SET_MODULE_OWNER (net); strcpy (net->name, "usb%d"); dev->cdc = cdc; dev->zlp = zlp; @@ -2578,11 +2644,12 @@ if (rndis_set_param_dev (dev->rndis_config, dev->net, &dev->stats, &dev->cdc_filter)) goto fail0; - if (rndis_set_param_vendor(dev->rndis_config, vendorID, - manufacturer)) + if (rndis_set_param_vendor (dev->rndis_config, vendorID, + manufacturer)) goto fail0; - if (rndis_set_param_medium(dev->rndis_config, - NDIS_MEDIUM_802_3, 0)) + if (rndis_set_param_medium (dev->rndis_config, + NDIS_MEDIUM_802_3, + 0)) goto fail0; INFO (dev, "RNDIS ready\n"); } diff -urN linux-2.6.24.2/drivers/usb/gadget/file_storage.c linux-2.6.24.2-vpac1/drivers/usb/gadget/file_storage.c --- linux-2.6.24.2/drivers/usb/gadget/file_storage.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/file_storage.c 2008-02-22 13:52:46.000000000 +0100 @@ -1,7 +1,7 @@ /* * file_storage.c -- File-backed USB Storage Gadget, for USB development * - * Copyright (C) 2003-2007 Alan Stern + * Copyright (C) 2003-2005 Alan Stern * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -217,11 +217,17 @@ */ -/* #define VERBOSE_DEBUG */ -/* #define DUMP_MSGS */ +#undef DEBUG +#undef VERBOSE +#undef DUMP_MSGS + +#include +#include +#include #include +#include #include #include #include @@ -229,10 +235,18 @@ #include #include #include +#include +#include #include #include #include +#include +#include +#include +#include #include +#include +#include #include #include #include @@ -240,7 +254,7 @@ #include #include -#include +#include #include "gadget_chips.h" @@ -249,7 +263,7 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "7 August 2007" +#define DRIVER_VERSION "28 November 2005" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -275,48 +289,57 @@ /*-------------------------------------------------------------------------*/ +#define xprintk(f,level,fmt,args...) \ + dev_printk(level , &(f)->gadget->dev , fmt , ## args) +#define yprintk(l,level,fmt,args...) \ + dev_printk(level , &(l)->dev , fmt , ## args) + #ifdef DEBUG +#define DBG(fsg,fmt,args...) \ + xprintk(fsg , KERN_DEBUG , fmt , ## args) #define LDBG(lun,fmt,args...) \ - dev_dbg(&(lun)->dev , fmt , ## args) + yprintk(lun , KERN_DEBUG , fmt , ## args) #define MDBG(fmt,args...) \ printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) #else +#define DBG(fsg,fmt,args...) \ + do { } while (0) #define LDBG(lun,fmt,args...) \ do { } while (0) #define MDBG(fmt,args...) \ do { } while (0) -#undef VERBOSE_DEBUG +#undef VERBOSE #undef DUMP_MSGS #endif /* DEBUG */ -#ifdef VERBOSE_DEBUG +#ifdef VERBOSE +#define VDBG DBG #define VLDBG LDBG #else +#define VDBG(fsg,fmt,args...) \ + do { } while (0) #define VLDBG(lun,fmt,args...) \ do { } while (0) -#endif /* VERBOSE_DEBUG */ +#endif /* VERBOSE */ +#define ERROR(fsg,fmt,args...) \ + xprintk(fsg , KERN_ERR , fmt , ## args) #define LERROR(lun,fmt,args...) \ - dev_err(&(lun)->dev , fmt , ## args) + yprintk(lun , KERN_ERR , fmt , ## args) + +#define WARN(fsg,fmt,args...) \ + xprintk(fsg , KERN_WARNING , fmt , ## args) #define LWARN(lun,fmt,args...) \ - dev_warn(&(lun)->dev , fmt , ## args) + yprintk(lun , KERN_WARNING , fmt , ## args) + +#define INFO(fsg,fmt,args...) \ + xprintk(fsg , KERN_INFO , fmt , ## args) #define LINFO(lun,fmt,args...) \ - dev_info(&(lun)->dev , fmt , ## args) + yprintk(lun , KERN_INFO , fmt , ## args) #define MINFO(fmt,args...) \ printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) -#define DBG(d, fmt, args...) \ - dev_dbg(&(d)->gadget->dev , fmt , ## args) -#define VDBG(d, fmt, args...) \ - dev_vdbg(&(d)->gadget->dev , fmt , ## args) -#define ERROR(d, fmt, args...) \ - dev_err(&(d)->gadget->dev , fmt , ## args) -#define WARN(d, fmt, args...) \ - dev_warn(&(d)->gadget->dev , fmt , ## args) -#define INFO(d, fmt, args...) \ - dev_info(&(d)->gadget->dev , fmt , ## args) - /*-------------------------------------------------------------------------*/ @@ -327,8 +350,8 @@ static struct { char *file[MAX_LUNS]; int ro[MAX_LUNS]; - unsigned int num_filenames; - unsigned int num_ros; + int num_filenames; + int num_ros; unsigned int nluns; int removable; @@ -555,7 +578,7 @@ #define backing_file_is_open(curlun) ((curlun)->filp != NULL) -static struct lun *dev_to_lun(struct device *dev) +static inline struct lun *dev_to_lun(struct device *dev) { return container_of(dev, struct lun, dev); } @@ -576,6 +599,7 @@ struct fsg_buffhd { void *buf; + dma_addr_t dma; enum fsg_buffer_state state; struct fsg_buffhd *next; @@ -662,6 +686,7 @@ int thread_wakeup_needed; struct completion thread_notifier; struct task_struct *thread_task; + sigset_t thread_signal_mask; int cmnd_size; u8 cmnd[MAX_COMMAND_SIZE]; @@ -688,13 +713,13 @@ typedef void (*fsg_routine_t)(struct fsg_dev *); -static int exception_in_progress(struct fsg_dev *fsg) +static int inline exception_in_progress(struct fsg_dev *fsg) { return (fsg->state > FSG_STATE_IDLE); } /* Make bulk-out requests be divisible by the maxpacket size */ -static void set_bulk_out_req_length(struct fsg_dev *fsg, +static void inline set_bulk_out_req_length(struct fsg_dev *fsg, struct fsg_buffhd *bh, unsigned int length) { unsigned int rem; @@ -720,36 +745,50 @@ static void dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) { - if (length < 512) { - DBG(fsg, "%s, length %u:\n", label, length); - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, - 16, 1, buf, length, 0); + unsigned int start, num, i; + char line[52], *p; + + if (length >= 512) + return; + DBG(fsg, "%s, length %u:\n", label, length); + + start = 0; + while (length > 0) { + num = min(length, 16u); + p = line; + for (i = 0; i < num; ++i) { + if (i == 8) + *p++ = ' '; + sprintf(p, " %02x", buf[i]); + p += 3; + } + *p = 0; + printk(KERN_DEBUG "%6x: %s\n", start, line); + buf += num; + start += num; + length -= num; } } -static void dump_cdb(struct fsg_dev *fsg) +static void inline dump_cdb(struct fsg_dev *fsg) {} #else -static void dump_msg(struct fsg_dev *fsg, const char *label, +static void inline dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) {} -#ifdef VERBOSE_DEBUG - -static void dump_cdb(struct fsg_dev *fsg) +static void inline dump_cdb(struct fsg_dev *fsg) { - print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, - 16, 1, fsg->cmnd, fsg->cmnd_size, 0); -} - -#else + int i; + char cmdbuf[3*MAX_COMMAND_SIZE + 1]; -static void dump_cdb(struct fsg_dev *fsg) -{} + for (i = 0; i < fsg->cmnd_size; ++i) + sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]); + VDBG(fsg, "SCSI CDB: %s\n", cmdbuf); +} -#endif /* VERBOSE_DEBUG */ #endif /* DUMP_MSGS */ @@ -772,24 +811,24 @@ /* Routines for unaligned data access */ -static u16 get_be16(u8 *buf) +static u16 inline get_be16(u8 *buf) { return ((u16) buf[0] << 8) | ((u16) buf[1]); } -static u32 get_be32(u8 *buf) +static u32 inline get_be32(u8 *buf) { return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | ((u32) buf[2] << 8) | ((u32) buf[3]); } -static void put_be16(u8 *buf, u16 val) +static void inline put_be16(u8 *buf, u16 val) { buf[0] = val >> 8; buf[1] = val; } -static void put_be32(u8 *buf, u32 val) +static void inline put_be32(u8 *buf, u32 val) { buf[0] = val >> 24; buf[1] = val >> 16; @@ -913,6 +952,8 @@ #define FS_FUNCTION_PRE_EP_ENTRIES 2 +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* * USB 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -975,14 +1016,14 @@ #define HS_FUNCTION_PRE_EP_ENTRIES 2 /* Maxpacket and other transfer characteristics vary by speed. */ -static struct usb_endpoint_descriptor * -ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, - struct usb_endpoint_descriptor *hs) -{ - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return hs; - return fs; -} +#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs)) + +#else + +/* If there's no high speed support, always use the full-speed descriptor. */ +#define ep_desc(g,fs,hs) fs + +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ /* The CBI specification limits the serial string to 12 uppercase hexadecimal @@ -1014,22 +1055,26 @@ static int populate_config_buf(struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { +#ifdef CONFIG_USB_GADGET_DUALSPEED enum usb_device_speed speed = gadget->speed; +#endif int len; const struct usb_descriptor_header **function; if (index > 0) return -EINVAL; - if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) +#ifdef CONFIG_USB_GADGET_DUALSPEED + if (type == USB_DT_OTHER_SPEED_CONFIG) speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; - if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH) + if (speed == USB_SPEED_HIGH) function = hs_function; else +#endif function = fs_function; /* for now, don't advertise srp-only devices */ - if (!gadget_is_otg(gadget)) + if (!gadget->is_otg) function++; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); @@ -1251,7 +1296,6 @@ struct usb_request *req = fsg->ep0req; int value = -EOPNOTSUPP; u16 w_index = le16_to_cpu(ctrl->wIndex); - u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); if (!fsg->config) @@ -1265,7 +1309,7 @@ if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; - if (w_index != 0 || w_value != 0) { + if (w_index != 0) { value = -EDOM; break; } @@ -1281,7 +1325,7 @@ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; - if (w_index != 0 || w_value != 0) { + if (w_index != 0) { value = -EDOM; break; } @@ -1300,7 +1344,7 @@ if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; - if (w_index != 0 || w_value != 0) { + if (w_index != 0) { value = -EDOM; break; } @@ -1351,9 +1395,10 @@ value = sizeof device_desc; memcpy(req->buf, &device_desc, value); break; +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: VDBG(fsg, "get device qualifier\n"); - if (!gadget_is_dualspeed(fsg->gadget)) + if (!fsg->gadget->is_dualspeed) break; value = sizeof dev_qualifier; memcpy(req->buf, &dev_qualifier, value); @@ -1361,12 +1406,15 @@ case USB_DT_OTHER_SPEED_CONFIG: VDBG(fsg, "get other-speed config descriptor\n"); - if (!gadget_is_dualspeed(fsg->gadget)) + if (!fsg->gadget->is_dualspeed) break; goto get_config; +#endif case USB_DT_CONFIG: VDBG(fsg, "get configuration descriptor\n"); -get_config: +#ifdef CONFIG_USB_GADGET_DUALSPEED + get_config: +#endif value = populate_config_buf(fsg->gadget, req->buf, w_value >> 8, @@ -1599,8 +1647,7 @@ /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) + if ((rc = sleep_thread(fsg)) != 0) return rc; } @@ -1839,8 +1886,7 @@ } /* Wait for something to happen */ - rc = sleep_thread(fsg); - if (rc) + if ((rc = sleep_thread(fsg)) != 0) return rc; } @@ -2324,8 +2370,7 @@ /* Wait for the next buffer to be free */ while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) + if ((rc = sleep_thread(fsg)) != 0) return rc; } @@ -2385,8 +2430,7 @@ } /* Otherwise wait for something to happen */ - rc = sleep_thread(fsg); - if (rc) + if ((rc = sleep_thread(fsg)) != 0) return rc; } return 0; @@ -2508,8 +2552,7 @@ /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) + if ((rc = sleep_thread(fsg)) != 0) return rc; } @@ -2569,6 +2612,7 @@ fsg->intr_buffhd = bh; // Point to the right buffhd fsg->intreq->buf = bh->inreq->buf; + fsg->intreq->dma = bh->inreq->dma; fsg->intreq->context = bh; start_transfer(fsg, fsg->intr_in, fsg->intreq, &fsg->intreq_busy, &bh->state); @@ -2729,10 +2773,9 @@ /* Wait for the next buffer to become available for data or status */ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) + if ((rc = sleep_thread(fsg)) != 0) return rc; - } + } fsg->phase_error = 0; fsg->short_packet_received = 0; @@ -2964,7 +3007,7 @@ /* Is the CBW meaningful? */ if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || - cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { + cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) { DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " "cmdlen %u\n", cbw->Lun, cbw->Flags, cbw->Length); @@ -3004,10 +3047,9 @@ /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) + if ((rc = sleep_thread(fsg)) != 0) return rc; - } + } /* Queue a request to read a Bulk-only CBW */ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); @@ -3021,10 +3063,9 @@ /* Wait for the CBW to arrive */ while (bh->state != BUF_STATE_FULL) { - rc = sleep_thread(fsg); - if (rc) + if ((rc = sleep_thread(fsg)) != 0) return rc; - } + } smp_rmb(); rc = received_cbw(fsg, bh); bh->state = BUF_STATE_EMPTY; @@ -3033,10 +3074,9 @@ /* Wait for the next command to arrive */ while (fsg->cbbuf_cmnd_size == 0) { - rc = sleep_thread(fsg); - if (rc) + if ((rc = sleep_thread(fsg)) != 0) return rc; - } + } /* Is the previous status interrupt request still busy? * The host is allowed to skip reading the status, @@ -3161,6 +3201,7 @@ if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0) goto reset; bh->inreq->buf = bh->outreq->buf = bh->buf; + bh->inreq->dma = bh->outreq->dma = bh->dma; bh->inreq->context = bh->outreq->context = bh; bh->inreq->complete = bulk_in_complete; bh->outreq->complete = bulk_out_complete; @@ -3236,7 +3277,8 @@ /* Clear the existing signals. Anything but SIGUSR1 is converted * into a high-priority EXIT exception. */ for (;;) { - sig = dequeue_signal_lock(current, ¤t->blocked, &info); + sig = dequeue_signal_lock(current, &fsg->thread_signal_mask, + &info); if (!sig) break; if (sig != SIGUSR1) { @@ -3389,13 +3431,10 @@ /* Allow the thread to be killed by a signal, but set the signal mask * to block everything but INT, TERM, KILL, and USR1. */ - allow_signal(SIGINT); - allow_signal(SIGTERM); - allow_signal(SIGKILL); - allow_signal(SIGUSR1); - - /* Allow the thread to be frozen */ - set_freezable(); + siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) | + sigmask(SIGTERM) | sigmask(SIGKILL) | + sigmask(SIGUSR1)); + sigprocmask(SIG_SETMASK, &fsg->thread_signal_mask, NULL); /* Arrange for userspace references to be interpreted as kernel * pointers. That way we can pass a kernel pointer to a routine @@ -3557,8 +3596,7 @@ return sprintf(buf, "%d\n", curlun->ro); } -static ssize_t show_file(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = dev_get_drvdata(dev); @@ -3567,8 +3605,8 @@ down_read(&fsg->filesem); if (backing_file_is_open(curlun)) { // Get the complete pathname - p = d_path(curlun->filp->f_path.dentry, - curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1); + p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt, + buf, PAGE_SIZE - 1); if (IS_ERR(p)) rc = PTR_ERR(p); else { @@ -3586,8 +3624,7 @@ } -static ssize_t store_ro(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); @@ -3611,8 +3648,7 @@ return rc; } -static ssize_t store_file(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = dev_get_drvdata(dev); @@ -3699,12 +3735,19 @@ } /* Free the data buffers */ - for (i = 0; i < NUM_BUFFERS; ++i) - kfree(fsg->buffhds[i].buf); + for (i = 0; i < NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + + if (bh->buf) + usb_ep_free_buffer(fsg->bulk_in, bh->buf, bh->dma, + mod_data.buflen); + } /* Free the request and buffer for endpoint 0 */ if (req) { - kfree(req->buf); + if (req->buf) + usb_ep_free_buffer(fsg->ep0, req->buf, + req->dma, EP0_BUFSIZE); usb_ep_free_request(fsg->ep0, req); } @@ -3806,6 +3849,7 @@ struct usb_ep *ep; struct usb_request *req; char *pathbuf, *p; + struct usb_endpoint_config ep_config; fsg->gadget = gadget; set_gadget_data(gadget, fsg); @@ -3824,7 +3868,7 @@ /* Find out how many LUNs there should be */ i = mod_data.nluns; if (i == 0) - i = max(mod_data.num_filenames, 1u); + i = max(mod_data.num_filenames, 1); if (i > MAX_LUNS) { ERROR(fsg, "invalid number of LUNs: %d\n", i); rc = -EINVAL; @@ -3876,21 +3920,25 @@ } /* Find all the endpoints we will use */ + ep_config.config = CONFIG_VALUE; + ep_config.interface = intf_desc.bInterfaceNumber; + ep_config.altinterface = intf_desc.bAlternateSetting; + usb_ep_autoconfig_reset(gadget); - ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc); + ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc, &ep_config, 1); if (!ep) goto autoconf_fail; ep->driver_data = fsg; // claim the endpoint fsg->bulk_in = ep; - ep = usb_ep_autoconfig(gadget, &fs_bulk_out_desc); + ep = usb_ep_autoconfig(gadget, &fs_bulk_out_desc, &ep_config, 1); if (!ep) goto autoconf_fail; ep->driver_data = fsg; // claim the endpoint fsg->bulk_out = ep; if (transport_is_cbi()) { - ep = usb_ep_autoconfig(gadget, &fs_intr_in_desc); + ep = usb_ep_autoconfig(gadget, &fs_intr_in_desc, &ep_config, 1); if (!ep) goto autoconf_fail; ep->driver_data = fsg; // claim the endpoint @@ -3909,31 +3957,31 @@ intf_desc.bInterfaceProtocol = mod_data.transport_type; fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL; - if (gadget_is_dualspeed(gadget)) { - hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; +#ifdef CONFIG_USB_GADGET_DUALSPEED + hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; + + /* Assume ep0 uses the same maxpacket value for both speeds */ + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; - /* Assume ep0 uses the same maxpacket value for both speeds */ - dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; + /* Assume that all endpoint addresses are the same for both speeds */ + hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress; + hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress; + hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress; +#endif - /* Assume endpoint addresses are the same for both speeds */ - hs_bulk_in_desc.bEndpointAddress = - fs_bulk_in_desc.bEndpointAddress; - hs_bulk_out_desc.bEndpointAddress = - fs_bulk_out_desc.bEndpointAddress; - hs_intr_in_desc.bEndpointAddress = - fs_intr_in_desc.bEndpointAddress; + if (gadget->is_otg) { + otg_desc.bmAttributes |= USB_OTG_HNP, + config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - if (gadget_is_otg(gadget)) - otg_desc.bmAttributes |= USB_OTG_HNP; - rc = -ENOMEM; /* Allocate the request and buffer for endpoint 0 */ fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL); if (!req) goto out; - req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL); + req->buf = usb_ep_alloc_buffer(fsg->ep0, EP0_BUFSIZE, + &req->dma, GFP_KERNEL); if (!req->buf) goto out; req->complete = ep0_complete; @@ -3945,7 +3993,8 @@ /* Allocate for the bulk-in endpoint. We assume that * the buffer will also work with the bulk-out (and * interrupt-in) endpoint. */ - bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL); + bh->buf = usb_ep_alloc_buffer(fsg->bulk_in, mod_data.buflen, + &bh->dma, GFP_KERNEL); if (!bh->buf) goto out; bh->next = bh + 1; @@ -4006,7 +4055,7 @@ DBG(fsg, "removable=%d, stall=%d, buflen=%u\n", mod_data.removable, mod_data.can_stall, mod_data.buflen); - DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task)); + DBG(fsg, "I/O thread pid: %d\n", fsg->thread_task->pid); set_bit(REGISTERED, &fsg->atomic_bitflags); diff -urN linux-2.6.24.2/drivers/usb/gadget/gadget_chips.h linux-2.6.24.2-vpac1/drivers/usb/gadget/gadget_chips.h --- linux-2.6.24.2/drivers/usb/gadget/gadget_chips.h 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/gadget_chips.h 2008-02-22 13:52:46.000000000 +0100 @@ -8,8 +8,6 @@ * (And avoiding all runtime comparisons in typical one-choice configs!) * * NOTE: some of these controller drivers may not be available yet. - * Some are available on 2.4 kernels; several are available, but not - * yet pushed in the 2.6 mainline tree. */ #ifdef CONFIG_USB_GADGET_NET2280 #define gadget_is_net2280(g) !strcmp("net2280", (g)->name) @@ -17,12 +15,6 @@ #define gadget_is_net2280(g) 0 #endif -#ifdef CONFIG_USB_GADGET_AMD5536UDC -#define gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name) -#else -#define gadget_is_amd5536udc(g) 0 -#endif - #ifdef CONFIG_USB_GADGET_DUMMY_HCD #define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name) #else @@ -32,7 +24,11 @@ #ifdef CONFIG_USB_GADGET_PXA2XX #define gadget_is_pxa(g) !strcmp("pxa2xx_udc", (g)->name) #else -#define gadget_is_pxa(g) 0 +# ifdef CONFIG_USB_GADGET_PXA27X +# define gadget_is_pxa(g) !strcmp("pxa27x_udc", (g)->name) +# else +# define gadget_is_pxa(g) 0 +# endif #endif #ifdef CONFIG_USB_GADGET_GOKU @@ -41,14 +37,12 @@ #define gadget_is_goku(g) 0 #endif -/* SH3 UDC -- not yet ported 2.4 --> 2.6 */ #ifdef CONFIG_USB_GADGET_SUPERH #define gadget_is_sh(g) !strcmp("sh_udc", (g)->name) #else #define gadget_is_sh(g) 0 #endif -/* not yet stable on 2.6 (would help "original Zaurus") */ #ifdef CONFIG_USB_GADGET_SA1100 #define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name) #else @@ -61,7 +55,6 @@ #define gadget_is_lh7a40x(g) 0 #endif -/* handhelds.org tree (?) */ #ifdef CONFIG_USB_GADGET_MQ11XX #define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name) #else @@ -74,24 +67,22 @@ #define gadget_is_omap(g) 0 #endif -/* not yet ported 2.4 --> 2.6 */ #ifdef CONFIG_USB_GADGET_N9604 #define gadget_is_n9604(g) !strcmp("n9604_udc", (g)->name) #else #define gadget_is_n9604(g) 0 #endif -/* various unstable versions available */ #ifdef CONFIG_USB_GADGET_PXA27X #define gadget_is_pxa27x(g) !strcmp("pxa27x_udc", (g)->name) #else #define gadget_is_pxa27x(g) 0 #endif -#ifdef CONFIG_USB_GADGET_ATMEL_USBA -#define gadget_is_atmel_usba(g) !strcmp("atmel_usba_udc", (g)->name) +#ifdef CONFIG_USB_GADGET_HUSB2DEV +#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name) #else -#define gadget_is_atmel_usba(g) 0 +#define gadget_is_husb2dev(g) 0 #endif #ifdef CONFIG_USB_GADGET_S3C2410 @@ -106,21 +97,13 @@ #define gadget_is_at91(g) 0 #endif -/* status unclear */ #ifdef CONFIG_USB_GADGET_IMX #define gadget_is_imx(g) !strcmp("imx_udc", (g)->name) #else #define gadget_is_imx(g) 0 #endif -#ifdef CONFIG_USB_GADGET_FSL_USB2 -#define gadget_is_fsl_usb2(g) !strcmp("fsl-usb2-udc", (g)->name) -#else -#define gadget_is_fsl_usb2(g) 0 -#endif - /* Mentor high speed function controller */ -/* from Montavista kernel (?) */ #ifdef CONFIG_USB_GADGET_MUSBHSFC #define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name) #else @@ -134,20 +117,12 @@ #define gadget_is_musbhdrc(g) 0 #endif -/* from Montavista kernel (?) */ #ifdef CONFIG_USB_GADGET_MPC8272 #define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name) #else #define gadget_is_mpc8272(g) 0 #endif -#ifdef CONFIG_USB_GADGET_M66592 -#define gadget_is_m66592(g) !strcmp("m66592_udc", (g)->name) -#else -#define gadget_is_m66592(g) 0 -#endif - - // CONFIG_USB_GADGET_SX2 // CONFIG_USB_GADGET_AU1X00 // ... @@ -204,13 +179,7 @@ return 0x16; else if (gadget_is_mpc8272(gadget)) return 0x17; - else if (gadget_is_atmel_usba(gadget)) + else if (gadget_is_husb2dev(gadget)) return 0x18; - else if (gadget_is_fsl_usb2(gadget)) - return 0x19; - else if (gadget_is_amd5536udc(gadget)) - return 0x20; - else if (gadget_is_m66592(gadget)) - return 0x21; return -ENOENT; } diff -urN linux-2.6.24.2/drivers/usb/gadget/gmidi.c linux-2.6.24.2-vpac1/drivers/usb/gadget/gmidi.c --- linux-2.6.24.2/drivers/usb/gadget/gmidi.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/gmidi.c 2008-02-22 13:52:46.000000000 +0100 @@ -18,11 +18,17 @@ * http://www.usb.org/developers/devclass_docs/midi10.pdf */ -/* #define VERBOSE_DEBUG */ +#define DEBUG 1 +// #define VERBOSE +#include #include +#include +#include +#include #include #include +#include #include #include @@ -30,7 +36,7 @@ #include #include -#include +#include #include #include @@ -133,16 +139,30 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req); -#define DBG(d, fmt, args...) \ - dev_dbg(&(d)->gadget->dev , fmt , ## args) -#define VDBG(d, fmt, args...) \ - dev_vdbg(&(d)->gadget->dev , fmt , ## args) -#define ERROR(d, fmt, args...) \ - dev_err(&(d)->gadget->dev , fmt , ## args) -#define WARN(d, fmt, args...) \ - dev_warn(&(d)->gadget->dev , fmt , ## args) -#define INFO(d, fmt, args...) \ - dev_info(&(d)->gadget->dev , fmt , ## args) +#define xprintk(d,level,fmt,args...) \ + dev_printk(level , &(d)->gadget->dev , fmt , ## args) + +#ifdef DEBUG +#define DBG(dev,fmt,args...) \ + xprintk(dev , KERN_DEBUG , fmt , ## args) +#else +#define DBG(dev,fmt,args...) \ + do { } while (0) +#endif /* DEBUG */ + +#ifdef VERBOSE +#define VDBG DBG +#else +#define VDBG(dev,fmt,args...) \ + do { } while (0) +#endif /* VERBOSE */ + +#define ERROR(dev,fmt,args...) \ + xprintk(dev , KERN_ERR , fmt , ## args) +#define WARN(dev,fmt,args...) \ + xprintk(dev , KERN_WARNING , fmt , ## args) +#define INFO(dev,fmt,args...) \ + xprintk(dev , KERN_INFO , fmt , ## args) static unsigned buflen = 256; @@ -405,7 +425,7 @@ return len; } -static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) +static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length) { struct usb_request *req; @@ -435,7 +455,7 @@ * Receives a chunk of MIDI data. */ static void gmidi_read_data(struct usb_ep *ep, int cable, - uint8_t *data, int length) + uint8_t* data, int length) { struct gmidi_device *dev = ep->driver_data; /* cable is ignored, because for now we only have one. */ @@ -521,7 +541,7 @@ { int err = 0; struct usb_request *req; - struct usb_ep *ep; + struct usb_ep* ep; unsigned i; err = usb_ep_enable(dev->in_ep, &bulk_in_desc); @@ -608,7 +628,7 @@ if (gadget_is_sa1100(gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ - ERROR(dev, "can't change configurations\n"); + INFO(dev, "can't change configurations\n"); return -ESPIPE; } gmidi_reset_config(dev); @@ -823,7 +843,7 @@ static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget) { struct gmidi_device *dev = get_gadget_data(gadget); - struct snd_card *card; + struct snd_card* card; DBG(dev, "unbind\n"); @@ -847,12 +867,12 @@ return 0; } -static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0, +static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0, uint8_t p1, uint8_t p2, uint8_t p3) { unsigned length = req->length; - u8 *buf = (u8 *)req->buf + length; + uint8_t* buf = (uint8_t*)req->buf + length; buf[0] = p0; buf[1] = p1; buf[2] = p2; @@ -863,8 +883,8 @@ /* * Converts MIDI commands to USB MIDI packets. */ -static void gmidi_transmit_byte(struct usb_request *req, - struct gmidi_in_port *port, uint8_t b) +static void gmidi_transmit_byte(struct usb_request* req, + struct gmidi_in_port* port, uint8_t b) { uint8_t p0 = port->cable; @@ -961,10 +981,10 @@ } } -static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req) +static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req) { - struct usb_ep *ep = dev->in_ep; - struct gmidi_in_port *port = &dev->in_port; + struct usb_ep* ep = dev->in_ep; + struct gmidi_in_port* port = &dev->in_port; if (!ep) { return; @@ -1000,14 +1020,14 @@ static void gmidi_in_tasklet(unsigned long data) { - struct gmidi_device *dev = (struct gmidi_device *)data; + struct gmidi_device* dev = (struct gmidi_device*)data; gmidi_transmit(dev, NULL); } static int gmidi_in_open(struct snd_rawmidi_substream *substream) { - struct gmidi_device *dev = substream->rmidi->private_data; + struct gmidi_device* dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_open\n"); dev->in_substream = substream; @@ -1017,15 +1037,13 @@ static int gmidi_in_close(struct snd_rawmidi_substream *substream) { - struct gmidi_device *dev = substream->rmidi->private_data; - VDBG(dev, "gmidi_in_close\n"); return 0; } static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) { - struct gmidi_device *dev = substream->rmidi->private_data; + struct gmidi_device* dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_trigger %d\n", up); dev->in_port.active = up; @@ -1036,7 +1054,7 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream) { - struct gmidi_device *dev = substream->rmidi->private_data; + struct gmidi_device* dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_open\n"); dev->out_substream = substream; @@ -1045,15 +1063,13 @@ static int gmidi_out_close(struct snd_rawmidi_substream *substream) { - struct gmidi_device *dev = substream->rmidi->private_data; - VDBG(dev, "gmidi_out_close\n"); return 0; } static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up) { - struct gmidi_device *dev = substream->rmidi->private_data; + struct gmidi_device* dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_trigger %d\n", up); if (up) { @@ -1232,11 +1248,17 @@ tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev); /* preallocate control response and buffer */ - dev->req = alloc_ep_req(gadget->ep0, USB_BUFSIZ); + dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); if (!dev->req) { err = -ENOMEM; goto fail; } + dev->req->buf = usb_ep_alloc_buffer(gadget->ep0, USB_BUFSIZ, + &dev->req->dma, GFP_KERNEL); + if (!dev->req->buf) { + err = -ENOMEM; + goto fail; + } dev->req->complete = gmidi_setup_complete; diff -urN linux-2.6.24.2/drivers/usb/gadget/inode.c linux-2.6.24.2-vpac1/drivers/usb/gadget/inode.c --- linux-2.6.24.2/drivers/usb/gadget/inode.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/inode.c 2008-02-22 13:52:46.000000000 +0100 @@ -20,7 +20,8 @@ */ -/* #define VERBOSE_DEBUG */ +// #define DEBUG /* data to help fault diagnosis */ +// #define VERBOSE /* extra debug messages (success too) */ #include #include @@ -36,8 +37,8 @@ #include #include -#include -#include +#include +#include /* @@ -252,7 +253,7 @@ do { } while (0) #endif /* DEBUG */ -#ifdef VERBOSE_DEBUG +#ifdef VERBOSE #define VDEBUG DBG #else #define VDEBUG(dev,fmt,args...) \ @@ -922,7 +923,7 @@ struct dev_data *dev = ep->driver_data; if (req->buf != dev->rbuf) { - kfree(req->buf); + usb_ep_free_buffer (ep, req->buf, req->dma, req->length); req->buf = dev->rbuf; req->dma = DMA_ADDR_INVALID; } @@ -962,8 +963,8 @@ return -EBUSY; } if (len > sizeof (dev->rbuf)) - req->buf = kmalloc(len, GFP_ATOMIC); - if (req->buf == NULL) { + req->buf = usb_ep_alloc_buffer (ep, len, &req->dma, GFP_ATOMIC); + if (req->buf == 0) { req->buf = dev->rbuf; return -ENOMEM; } @@ -1009,12 +1010,11 @@ /* assume that was SET_CONFIGURATION */ if (dev->current_config) { unsigned power; - - if (gadget_is_dualspeed(dev->gadget) - && (dev->gadget->speed - == USB_SPEED_HIGH)) +#ifdef CONFIG_USB_GADGET_DUALSPEED + if (dev->gadget->speed == USB_SPEED_HIGH) power = dev->hs_config->bMaxPower; else +#endif power = dev->config->bMaxPower; usb_gadget_vbus_draw(dev->gadget, 2 * power); } @@ -1355,23 +1355,26 @@ config_buf (struct dev_data *dev, u8 type, unsigned index) { int len; - int hs = 0; +#ifdef CONFIG_USB_GADGET_DUALSPEED + int hs; +#endif /* only one configuration */ if (index > 0) return -EINVAL; - if (gadget_is_dualspeed(dev->gadget)) { - hs = (dev->gadget->speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; - } +#ifdef CONFIG_USB_GADGET_DUALSPEED + hs = (dev->gadget->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; if (hs) { dev->req->buf = dev->hs_config; - len = le16_to_cpu(dev->hs_config->wTotalLength); - } else { + len = le16_to_cpup (&dev->hs_config->wTotalLength); + } else +#endif + { dev->req->buf = dev->config; - len = le16_to_cpu(dev->config->wTotalLength); + len = le16_to_cpup (&dev->config->wTotalLength); } ((u8 *)dev->req->buf) [1] = type; return len; @@ -1390,13 +1393,13 @@ spin_lock (&dev->lock); dev->setup_abort = 0; if (dev->state == STATE_DEV_UNCONNECTED) { - if (gadget_is_dualspeed(gadget) - && gadget->speed == USB_SPEED_HIGH - && dev->hs_config == NULL) { +#ifdef CONFIG_USB_GADGET_DUALSPEED + if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) { spin_unlock(&dev->lock); ERROR (dev, "no high speed config??\n"); return -EINVAL; } +#endif /* CONFIG_USB_GADGET_DUALSPEED */ dev->state = STATE_DEV_CONNECTED; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; @@ -1466,12 +1469,13 @@ // user mode expected to disable endpoints } else { u8 config, power; - - if (gadget_is_dualspeed(gadget) - && gadget->speed == USB_SPEED_HIGH) { +#ifdef CONFIG_USB_GADGET_DUALSPEED + if (gadget->speed == USB_SPEED_HIGH) { config = dev->hs_config->bConfigurationValue; power = dev->hs_config->bMaxPower; - } else { + } else +#endif + { config = dev->config->bConfigurationValue; power = dev->config->bMaxPower; } @@ -1501,7 +1505,7 @@ } break; -#ifndef CONFIG_USB_GADGET_PXA2XX +#ifndef CONFIG_USB_GADGETFS_PXA2XX /* PXA automagically handles this request too */ case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != 0x80) @@ -1881,7 +1885,7 @@ /* full or low speed config */ dev->config = (void *) kbuf; - total = le16_to_cpu(dev->config->wTotalLength); + total = le16_to_cpup (&dev->config->wTotalLength); if (!is_valid_config (dev->config) || total >= length) goto fail; kbuf += total; @@ -1890,7 +1894,7 @@ /* optional high speed config */ if (kbuf [1] == USB_DT_CONFIG) { dev->hs_config = (void *) kbuf; - total = le16_to_cpu(dev->hs_config->wTotalLength); + total = le16_to_cpup (&dev->hs_config->wTotalLength); if (!is_valid_config (dev->hs_config) || total >= length) goto fail; kbuf += total; diff -urN linux-2.6.24.2/drivers/usb/gadget/Kconfig linux-2.6.24.2-vpac1/drivers/usb/gadget/Kconfig --- linux-2.6.24.2/drivers/usb/gadget/Kconfig 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/Kconfig 2008-02-22 13:52:46.000000000 +0100 @@ -196,11 +196,38 @@ # don't waste memory for the other endpoints config USB_PXA2XX_SMALL depends on USB_GADGET_PXA2XX - bool + bool "Handle only three endpoints (driver smaller by 1K)" default n if USB_ETH_RNDIS default y if USB_ZERO default y if USB_ETH default y if USB_G_SERIAL + help + Use this option if you're really really short on memory + and your gadget driver needs only one IN and one OUT bulk + endpoints. This is enough for most simple gadgets (gadget + zero, serial, ethernet and such). + +config USB_GADGET_PXA27X + boolean "PXA 27x" + depends on ARCH_PXA && PXA27x + help + Intel's PXA 27x series XScale ARM-5TE processors include + an integrated full speed USB 1.1 device controller. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "pxa27x_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_PXA27X + tristate + depends on USB_GADGET_PXA27X + default USB_GADGET + select USB_GADGET_SELECTED + +config USB_PXA27X_DMA + bool # "Use DMA support" + depends on USB_GADGET_PXA27X + default n config USB_GADGET_M66592 boolean "Renesas M66592 USB Peripheral Controller" @@ -474,6 +501,8 @@ XP, you'll need to download drivers from Microsoft's website; a URL is given in comments found in that info file. + This breaks ETH support on PXA hosts. + config USB_GADGETFS tristate "Gadget Filesystem (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -538,6 +567,11 @@ Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_midi". +config USB_G_CHAR + tristate "Character Gadget" + help + Character Gadget is what usb-char used to be. Have fun. + # put drivers that need isochronous transfer support (for audio # or video class gadget drivers), or specific hardware, here. @@ -546,4 +580,14 @@ endchoice +config USB_PXA2XX_GPIO + boolean "Use GPIOs to control pxa2xx_udc driver" + depends on (USB_GADGET_PXA2XX || USB_GADGET_PXA27X) + help + pxa2xx_udc requires machine-specific methods to handle + connection detection and pull up control. Many machines + use GPIOs for these. This driver allows to just specify + these GPIOs, without writing duplicate functions to + get/set these GPIOs. + endmenu diff -urN linux-2.6.24.2/drivers/usb/gadget/Makefile linux-2.6.24.2-vpac1/drivers/usb/gadget/Makefile --- linux-2.6.24.2/drivers/usb/gadget/Makefile 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/Makefile 2008-02-22 13:52:46.000000000 +0100 @@ -13,6 +13,7 @@ obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o +obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o obj-$(CONFIG_USB_AT91) += at91_udc.o obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o @@ -28,6 +29,7 @@ gadgetfs-objs := inode.o g_file_storage-objs := file_storage.o usbstring.o config.o \ epautoconf.o +g_char-objs := usbstring.o char.o epautoconf.o ifeq ($(CONFIG_USB_ETH_RNDIS),y) g_ether-objs += rndis.o @@ -39,4 +41,6 @@ obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o obj-$(CONFIG_USB_G_SERIAL) += g_serial.o obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o +obj-$(CONFIG_USB_G_CHAR) += g_char.o +obj-$(CONFIG_USB_PXA2XX_GPIO) += pxa2xx_udc_gpio.o diff -urN linux-2.6.24.2/drivers/usb/gadget/pxa27x_udc.c linux-2.6.24.2-vpac1/drivers/usb/gadget/pxa27x_udc.c --- linux-2.6.24.2/drivers/usb/gadget/pxa27x_udc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/pxa27x_udc.c 2008-02-22 13:52:46.000000000 +0100 @@ -0,0 +1,2439 @@ +/* + * Handles the Intel 27x USB Device Controller (UDC) + * + * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) + * Copyright (C) 2003 Robert Schwebel, Pengutronix + * Copyright (C) 2003 Benedikt Spranger, Pengutronix + * Copyright (C) 2003 David Brownell + * Copyright (C) 2003 Joshua Wise + * Copyright (C) 2004 Intel Corporation + * Copyright (C) 2005 SDG Systems, LLC (Aric Blumer) + * Copyright (C) 2005-2006 Openedhand Ltd. (Richard Purdie) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#undef DEBUG +//#define DEBUG 1 + //#define VERBOSE DBG_VERBOSE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/* + * This driver handles the USB Device Controller (UDC) in Intel's PXA 27x + * series processors. + * + * Such controller drivers work with a gadget driver. The gadget driver + * returns descriptors, implements configuration and data protocols used + * by the host to interact with this device, and allocates endpoints to + * the different protocol interfaces. The controller driver virtualizes + * usb hardware so that the gadget drivers will be more portable. + * + * This UDC hardware wants to implement a bit too much USB protocol. The + * biggest issue is that the endpoints have to be setup before the controller + * can be enabled and each endpoint can only have one configuration, interface + * and alternative interface number. Once enabled, these cannot be changed + * without a controller reset. + * + * Intel Errata #22 mentions issues when changing alternate interface. + * The exact meaning of this remains uncertain as gadget drivers using alternate + * interfaces such as CDC-Ethernet appear to work... + */ + +#define DRIVER_VERSION "01-01-2006" +#define DRIVER_DESC "PXA 27x USB Device Controller driver" + +static const char driver_name [] = "pxa27x_udc"; + +static const char ep0name [] = "ep0"; + + +#define USE_DMA +//#define DISABLE_TEST_MODE + +#ifdef CONFIG_PROC_FS +#define UDC_PROC_FILE +#endif + +#include "pxa27x_udc.h" + +#ifdef USE_DMA +static int use_dma = 1; +module_param(use_dma, bool, 0); +MODULE_PARM_DESC(use_dma, "true to use dma"); + +static void dma_nodesc_handler(int dmach, void *_ep); +static void kick_dma(struct pxa27x_ep *ep, struct pxa27x_request *req); + +#define DMASTR " (dma support)" + +#else /* !USE_DMA */ +#define DMASTR " (pio only)" +#endif + +#ifdef CONFIG_USB_PXA27X_SMALL +#define SIZE_STR " (small)" +#else +#define SIZE_STR "" +#endif + +#ifdef DISABLE_TEST_MODE +/* (mode == 0) == no undocumented chip tweaks + * (mode & 1) == double buffer bulk IN + * (mode & 2) == double buffer bulk OUT + * ... so mode = 3 (or 7, 15, etc) does it for both + */ +static ushort fifo_mode = 0; +module_param(fifo_mode, ushort, 0); +MODULE_PARM_DESC (fifo_mode, "pxa27x udc fifo mode"); +#endif + +#define UDCISR0_IR0 0x3 +#define UDCISR_INT_MASK (UDC_INT_FIFOERROR | UDC_INT_PACKETCMP) +#define UDCICR_INT_MASK UDCISR_INT_MASK + +#define UDCCSR_MASK (UDCCSR_FST | UDCCSR_DME) + +static void pxa27x_ep_fifo_flush(struct usb_ep *ep); +static void nuke(struct pxa27x_ep *, int status); +static void udc_init_ep(struct pxa27x_udc *dev); + + +/* + * Endpoint Functions + */ +static void pio_irq_enable(int ep_num) +{ + if (ep_num < 16) + UDCICR0 |= 3 << (ep_num * 2); + else { + ep_num -= 16; + UDCICR1 |= 3 << (ep_num * 2); + } +} + +static void pio_irq_disable(int ep_num) +{ + ep_num &= 0xf; + if (ep_num < 16) + UDCICR0 &= ~(3 << (ep_num * 2)); + else { + ep_num -= 16; + UDCICR1 &= ~(3 << (ep_num * 2)); + } +} + +/* The UDCCR reg contains mask and interrupt status bits, + * so using '|=' isn't safe as it may ack an interrupt. + */ +#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_UDE) + +static inline void udc_set_mask_UDCCR(int mask) +{ + UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS); +} + +static inline void udc_clear_mask_UDCCR(int mask) +{ + UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS); +} + +static inline void udc_ack_int_UDCCR(int mask) +{ + /* udccr contains the bits we dont want to change */ + __u32 udccr = UDCCR & UDCCR_MASK_BITS; + + UDCCR = udccr | (mask & ~UDCCR_MASK_BITS); +} + +/* + * Endpoint enable/disable + * + * Not much to do here as the ep_alloc function sets up most things. Once + * enabled, not much of the pxa27x configuration can be changed. + * + */ +static int pxa27x_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ + struct pxa27x_virt_ep *virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); + struct pxa27x_ep *ep = virt_ep->pxa_ep; + struct pxa27x_udc *dev; + + if (!_ep || !desc || _ep->name == ep0name + || desc->bDescriptorType != USB_DT_ENDPOINT + || ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) { + dev_err(ep->dev->dev, "%s, bad ep or descriptor\n", __FUNCTION__); + return -EINVAL; + } + + /* xfer types must match, except that interrupt ~= bulk */ + if( ep->ep_type != USB_ENDPOINT_XFER_BULK + && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { + dev_err(ep->dev->dev, "%s, %s type mismatch\n", __FUNCTION__, _ep->name); + return -EINVAL; + } + + /* hardware _could_ do smaller, but driver doesn't */ + if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK + && le16_to_cpu (desc->wMaxPacketSize) + != BULK_FIFO_SIZE) + || !desc->wMaxPacketSize) { + dev_err(ep->dev->dev, "%s, bad %s maxpacket\n", __FUNCTION__, _ep->name); + return -ERANGE; + } + + dev = ep->dev; + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + dev_err(ep->dev->dev, "%s, bogus device state\n", __FUNCTION__); + return -ESHUTDOWN; + } + + ep->desc = desc; + ep->dma = -1; + ep->stopped = 0; + ep->pio_irqs = ep->dma_irqs = 0; + ep->usb_ep->maxpacket = le16_to_cpu(desc->wMaxPacketSize); + + /* flush fifo (mostly for OUT buffers) */ + pxa27x_ep_fifo_flush(_ep); + + /* ... reset halt state too, if we could ... */ + +#ifdef USE_DMA + /* for (some) bulk and ISO endpoints, try to get a DMA channel and + * bind it to the endpoint. otherwise use PIO. + */ + dev_dbg(ep->dev->dev, "%s: called attributes=%d\n", __FUNCTION__, ep->ep_type); + switch (ep->ep_type) { + case USB_ENDPOINT_XFER_ISOC: + if (le16_to_cpu(desc->wMaxPacketSize) % 32) + break; + // fall through + case USB_ENDPOINT_XFER_BULK: + if (!use_dma || !ep->reg_drcmr) + break; + ep->dma = pxa_request_dma((char *)_ep->name, (le16_to_cpu(desc->wMaxPacketSize) > 64) + ? DMA_PRIO_MEDIUM : DMA_PRIO_LOW, dma_nodesc_handler, ep); + if (ep->dma >= 0) { + *ep->reg_drcmr = DRCMR_MAPVLD | ep->dma; + dev_dbg(ep->dev->dev, "%s using dma%d\n", _ep->name, ep->dma); + } + default: + break; + } +#endif + DBG(DBG_VERBOSE, "enabled %s\n", _ep->name); + return 0; +} + +static int pxa27x_ep_disable(struct usb_ep *_ep) +{ + struct pxa27x_virt_ep *virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); + struct pxa27x_ep *ep = virt_ep->pxa_ep; + unsigned long flags; + + if (!_ep || !ep->desc) { + dev_err(ep->dev->dev, "%s, %s not enabled\n", __FUNCTION__, + _ep ? _ep->name : NULL); + return -EINVAL; + } + local_irq_save(flags); + nuke(ep, -ESHUTDOWN); + +#ifdef USE_DMA + if (ep->dma >= 0) { + *ep->reg_drcmr = 0; + pxa_free_dma(ep->dma); + ep->dma = -1; + } +#endif + + /* flush fifo (mostly for IN buffers) */ + pxa27x_ep_fifo_flush(_ep); + + ep->desc = 0; + ep->stopped = 1; + + local_irq_restore(flags); + DBG(DBG_VERBOSE, "%s disabled\n", _ep->name); + return 0; +} + + + +/* for the pxa27x, these can just wrap kmalloc/kfree. gadget drivers + * must still pass correctly initialized endpoints, since other controller + * drivers may care about how it's currently set up (dma issues etc). + */ + +/* + * pxa27x_ep_alloc_request - allocate a request data structure + */ +static struct usb_request * +pxa27x_ep_alloc_request(struct usb_ep *_ep, unsigned gfp_flags) +{ + struct pxa27x_request *req; + + req = kzalloc(sizeof *req, gfp_flags); + if (!req) + return 0; + + INIT_LIST_HEAD(&req->queue); + return &req->req; +} + + +/* + * pxa27x_ep_free_request - deallocate a request data structure + */ +static void +pxa27x_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct pxa27x_request *req; + + req = container_of(_req, struct pxa27x_request, req); + WARN_ON(!list_empty(&req->queue)); + kfree(req); +} + + +/* PXA cache needs flushing with DMA I/O (it's dma-incoherent), but there's + * no device-affinity and the heap works perfectly well for i/o buffers. + * It wastes much less memory than dma_alloc_coherent() would, and even + * prevents cacheline (32 bytes wide) sharing problems. + */ +static void * +pxa27x_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, unsigned gfp_flags) +{ + char *retval; + + retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA|__GFP_HIGHMEM)); + if (retval) + *dma = virt_to_bus(retval); + return retval; +} + +static void +pxa27x_ep_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma, unsigned bytes) +{ + kfree(buf); +} + +/*-------------------------------------------------------------------------*/ + +/* + * done - retire a request; caller blocked irqs + */ +static void done(struct pxa27x_ep *ep, struct pxa27x_request *req, int status) +{ + list_del_init(&req->queue); + if (likely (req->req.status == -EINPROGRESS)) + req->req.status = status; + else + status = req->req.status; + + if (status && status != -ESHUTDOWN) + DBG(DBG_VERBOSE, "complete %s req %p stat %d len %u/%u\n", + ep->usb_ep->name, &req->req, status, + req->req.actual, req->req.length); + + /* don't modify queue heads during completion callback */ + req->req.complete(ep->usb_ep, &req->req); +} + + +static inline void ep0_idle(struct pxa27x_udc *dev) +{ + dev->ep0state = EP0_IDLE; +} + +static int write_packet(volatile u32 *uddr, struct pxa27x_request *req, unsigned max) +{ + u32 *buf; + int length, count, remain; + + buf = (u32*)(req->req.buf + req->req.actual); + prefetch(buf); + + /* how big will this packet be? */ + length = min(req->req.length - req->req.actual, max); + req->req.actual += length; + + remain = length & 0x3; + count = length & ~(0x3); + + //dev_dbg(ep->dev->dev, "Length %d, Remain %d, Count %d\n",length, remain, count); + + while (likely(count)) { + //dev_dbg(ep->dev->dev, "Sending:0x%x\n", *buf); + *uddr = *buf++; + count -= 4; + } + + if (remain) { + volatile u8* reg=(u8*)uddr; + char *rd =(u8*)buf; + + while (remain--) { + *reg=*rd++; + } + } + + return length; +} + +/* + * write to an IN endpoint fifo, as many packets as possible. + * irqs will use this to write the rest later. + * caller guarantees at least one packet buffer is ready (or a zlp). + */ +static int +write_fifo(struct pxa27x_ep *ep, struct pxa27x_request *req) +{ + unsigned max; + + max = le16_to_cpu(ep->desc->wMaxPacketSize); + do { + int count, is_last, is_short; + + //dev_dbg(ep->dev->dev, "write_fifo7 %x\n", *ep->reg_udccsr); + + if (*ep->reg_udccsr & UDCCSR_PC) { + //dev_dbg(ep->dev->dev, "Transmit Complete\n"); + *ep->reg_udccsr = UDCCSR_PC | (*ep->reg_udccsr & UDCCSR_MASK); + } + + if (*ep->reg_udccsr & UDCCSR_TRN) { + //dev_dbg(ep->dev->dev, "Clearing Underrun\n"); + *ep->reg_udccsr = UDCCSR_TRN | (*ep->reg_udccsr & UDCCSR_MASK); + } + //dev_dbg(ep->dev->dev, "write_fifo8 %x\n", *ep->reg_udccsr); + + count = write_packet(ep->reg_udcdr, req, max); + + /* last packet is usually short (or a zlp) */ + if (unlikely (count != max)) + is_last = is_short = 1; + else { + if (likely(req->req.length != req->req.actual) + || req->req.zero) + is_last = 0; + else + is_last = 1; + /* interrupt/iso maxpacket may not fill the fifo */ + is_short = unlikely (max < ep->fifo_size); + } + + //dev_dbg(ep->dev->dev, "write_fifo0 %x\n", *ep->reg_udccsr); + + dev_dbg(ep->dev->dev, "wrote %s count:%d bytes%s%s %d left %p\n", + ep->usb_ep->name, count, + is_last ? "/L" : "", is_short ? "/S" : "", + req->req.length - req->req.actual, &req->req); + + /* let loose that packet. maybe try writing another one, + * double buffering might work. + */ + *ep->reg_udccsr = UDCCSR_PC; + if (is_short) + *ep->reg_udccsr = UDCCSR_SP | (*ep->reg_udccsr & UDCCSR_MASK); + + dev_dbg(ep->dev->dev, "write_fifo0.5 %x\n", *ep->reg_udccsr); + + /* requests complete when all IN data is in the FIFO */ + if (is_last) { + done(ep, req, 0); + if (list_empty(&ep->queue) || unlikely(ep->dma >= 0)) { + pio_irq_disable(ep->pxa_ep_num); + //dev_dbg(ep->dev->dev, "write_fifo1 %x\n", *ep->reg_udccsr); +#ifdef USE_DMA + /* unaligned data and zlps couldn't use dma */ + if (unlikely(!list_empty(&ep->queue))) { + req = list_entry(ep->queue.next, + struct pxa27x_request, queue); + kick_dma(ep,req); + return 0; + } +#endif + } + //dev_dbg(ep->dev->dev, "write_fifo2 %x\n", *ep->reg_udccsr); + return 1; + } + + // TODO experiment: how robust can fifo mode tweaking be? + // double buffering is off in the default fifo mode, which + // prevents TFS from being set here. + + } while (*ep->reg_udccsr & UDCCSR_FS); + //dev_dbg(ep->dev->dev, "write_fifo2 %x\n", *ep->reg_udccsr); + return 0; +} + +/* caller asserts req->pending (ep0 irq status nyet cleared); starts + * ep0 data stage. these chips want very simple state transitions. + */ +static inline +void ep0start(struct pxa27x_udc *dev, u32 flags, const char *tag) +{ + UDCCSR0 = flags|UDCCSR0_SA|UDCCSR0_OPC; + UDCISR0 = UDCICR_INT(0, UDC_INT_FIFOERROR | UDC_INT_PACKETCMP); + dev->req_pending = 0; + DBG(DBG_VERY_NOISY, "%s %s, %02x/%02x\n", + __FUNCTION__, tag, UDCCSR0, flags); +} + +static int +write_ep0_fifo(struct pxa27x_ep *ep, struct pxa27x_request *req) +{ + unsigned count; + int is_short; + + count = write_packet(&UDCDR0, req, EP0_FIFO_SIZE); + ep->dev->stats.write.bytes += count; + + /* last packet "must be" short (or a zlp) */ + is_short = (count != EP0_FIFO_SIZE); + + DBG(DBG_VERY_NOISY, "ep0in %d bytes %d left %p\n", count, + req->req.length - req->req.actual, &req->req); + + if (unlikely (is_short)) { + if (ep->dev->req_pending) + ep0start(ep->dev, UDCCSR0_IPR, "short IN"); + else + UDCCSR0 = UDCCSR0_IPR; + + count = req->req.length; + done(ep, req, 0); + ep0_idle(ep->dev); +#if 0 + /* This seems to get rid of lost status irqs in some cases: + * host responds quickly, or next request involves config + * change automagic, or should have been hidden, or ... + * + * FIXME get rid of all udelays possible... + */ + if (count >= EP0_FIFO_SIZE) { + count = 100; + do { + if ((UDCCSR0 & UDCCSR0_OPC) != 0) { + /* clear OPC, generate ack */ + UDCCSR0 = UDCCSR0_OPC; + break; + } + count--; + udelay(1); + } while (count); + } +#endif + } else if (ep->dev->req_pending) + ep0start(ep->dev, 0, "IN"); + return is_short; +} + + +/* + * read_fifo - unload packet(s) from the fifo we use for usb OUT + * transfers and put them into the request. caller should have made + * sure there's at least one packet ready. + * + * returns true if the request completed because of short packet or the + * request buffer having filled (and maybe overran till end-of-packet). + */ +static int read_fifo(struct pxa27x_ep *ep, struct pxa27x_request *req) +{ + for (;;) { + u32 *buf; + int bufferspace, count, is_short; + + /* make sure there's a packet in the FIFO.*/ + if (unlikely ((*ep->reg_udccsr & UDCCSR_PC) == 0)) + break; + buf =(u32*) (req->req.buf + req->req.actual); + prefetchw(buf); + bufferspace = req->req.length - req->req.actual; + + /* read all bytes from this packet */ + if (likely (*ep->reg_udccsr & UDCCSR_BNE)) { + count = 0x3ff & *ep->reg_udcbcr; + req->req.actual += min(count, bufferspace); + } else /* zlp */ + count = 0; + + is_short = (count < ep->usb_ep->maxpacket); + dev_dbg(ep->dev->dev, "read %s udccsr:%02x, count:%d bytes%s req %p %d/%d\n", + ep->usb_ep->name, *ep->reg_udccsr, count, + is_short ? "/S" : "", + &req->req, req->req.actual, req->req.length); + + count = min(count, bufferspace); + while (likely (count > 0)) { + *buf++ = *ep->reg_udcdr; + count -= 4; + } + dev_dbg(ep->dev->dev, "Buf:0x%p\n", req->req.buf); + + *ep->reg_udccsr = UDCCSR_PC; + /* RPC/RSP/RNE could now reflect the other packet buffer */ + + /* completion */ + if (is_short || req->req.actual == req->req.length) { + done(ep, req, 0); + if (list_empty(&ep->queue)) + pio_irq_disable(ep->pxa_ep_num); + return 1; + } + + /* finished that packet. the next one may be waiting... */ + } + return 0; +} + +/* + * special ep0 version of the above. no UBCR0 or double buffering; status + * handshaking is magic. most device protocols don't need control-OUT. + * CDC vendor commands (and RNDIS), mass storage CB/CBI, and some other + * protocols do use them. + */ +static int read_ep0_fifo(struct pxa27x_ep *ep, struct pxa27x_request *req) +{ + u32 *buf, word; + unsigned bufferspace; + + buf = (u32*) (req->req.buf + req->req.actual); + bufferspace = req->req.length - req->req.actual; + + while (UDCCSR0 & UDCCSR0_RNE) { + word = UDCDR0; + + if (unlikely (bufferspace == 0)) { + /* this happens when the driver's buffer + * is smaller than what the host sent. + * discard the extra data. + */ + if (req->req.status != -EOVERFLOW) + dev_info(ep->dev->dev, "%s overflow\n", ep->usb_ep->name); + req->req.status = -EOVERFLOW; + } else { + *buf++ = word; + req->req.actual += 4; + bufferspace -= 4; + } + } + + UDCCSR0 = UDCCSR0_OPC ; + + /* completion */ + if (req->req.actual >= req->req.length) + return 1; + + /* finished that packet. the next one may be waiting... */ + return 0; +} + +#ifdef USE_DMA + +#define MAX_IN_DMA ((DCMD_LENGTH + 1) - BULK_FIFO_SIZE) +static void kick_dma(struct pxa27x_ep *ep, struct pxa27x_request *req) +{ + u32 dcmd = 0; + u32 len = req->req.length; + u32 buf = req->req.dma; + u32 fifo = io_v2p((u32)ep->reg_udcdr); + + buf += req->req.actual; + len -= req->req.actual; + ep->dma_con = 0; + + DMSG("%s: req:0x%p length:%d, actual:%d dma:%d\n", + __FUNCTION__, &req->req, req->req.length, + req->req.actual,ep->dma); + + /* no-descriptor mode can be simple for bulk-in, iso-in, iso-out */ + DCSR(ep->dma) = DCSR_NODESC; + if (buf & 0x3) + DALGN |= 1 << ep->dma; + else + DALGN &= ~(1 << ep->dma); + + if (ep->dir_in) { + DSADR(ep->dma) = buf; + DTADR(ep->dma) = fifo; + if (len > MAX_IN_DMA) { + len= MAX_IN_DMA; + ep->dma_con =1 ; + } else if (len >= ep->usb_ep->maxpacket) { + if ((ep->dma_con = (len % ep->usb_ep->maxpacket) != 0)) + len = ep->usb_ep->maxpacket; + } + dcmd = len | DCMD_BURST32 | DCMD_WIDTH4 | DCMD_ENDIRQEN + | DCMD_FLOWTRG | DCMD_INCSRCADDR; + } else { + DSADR(ep->dma) = fifo; + DTADR(ep->dma) = buf; + dcmd = len | DCMD_BURST32 | DCMD_WIDTH4 | DCMD_ENDIRQEN + | DCMD_FLOWSRC | DCMD_INCTRGADDR; + } + *ep->reg_udccsr = UDCCSR_DME; + DCMD(ep->dma) = dcmd; + DCSR(ep->dma) = DCSR_NODESC | DCSR_EORIRQEN \ + | ((ep->dir_in) ? DCSR_STOPIRQEN : 0); + *ep->reg_drcmr = ep->dma | DRCMR_MAPVLD; + DCSR(ep->dma) |= DCSR_RUN; +} + +static void cancel_dma(struct pxa27x_ep *ep) +{ + struct pxa27x_request *req; + u32 tmp; + + if (DCSR(ep->dma) == 0 || list_empty(&ep->queue)) + return; + + DMSG("hehe dma:%d,dcsr:0x%x\n", ep->dma, DCSR(ep->dma)); + DCSR(ep->dma) = 0; + while ((DCSR(ep->dma) & DCSR_STOPSTATE) == 0) + cpu_relax(); + + req = list_entry(ep->queue.next, struct pxa27x_request, queue); + tmp = DCMD(ep->dma) & DCMD_LENGTH; + req->req.actual = req->req.length - tmp; + + /* the last tx packet may be incomplete, so flush the fifo. + * FIXME correct req.actual if we can + */ + *ep->reg_udccsr = UDCCSR_FEF; +} + +static void dma_nodesc_handler(int dmach, void *_ep) +{ + struct pxa27x_ep *ep = _ep; + struct pxa27x_request *req, *req_next; + u32 dcsr, tmp, completed; + + local_irq_disable(); + + req = list_entry(ep->queue.next, struct pxa27x_request, queue); + + DMSG("%s, buf:0x%p\n",__FUNCTION__, req->req.buf); + + ep->dma_irqs++; + ep->dev->stats.irqs++; + + completed = 0; + + dcsr = DCSR(dmach); + DCSR(ep->dma) &= ~DCSR_RUN; + + if (dcsr & DCSR_BUSERR) { + DCSR(dmach) = DCSR_BUSERR; + dev_err(ep->dev->dev, "DMA Bus Error\n"); + req->req.status = -EIO; + completed = 1; + } else if (dcsr & DCSR_ENDINTR) { + DCSR(dmach) = DCSR_ENDINTR; + if (ep->dir_in) { + tmp = req->req.length - req->req.actual; + /* Last packet is a short one*/ + if (tmp < ep->usb_ep->maxpacket) { + int count = 0; + + *ep->reg_udccsr = UDCCSR_SP | \ + (*ep->reg_udccsr & UDCCSR_MASK); + /*Wait for packet out */ + while( (count++ < 10000) && \ + !(*ep->reg_udccsr & UDCCSR_FS)); + if (count >= 10000) + DMSG("Failed to send packet\n"); + else + DMSG("%s: short packet sent len:%d," + "length:%d,actual:%d\n", __FUNCTION__, + tmp, req->req.length, req->req.actual); + req->req.actual = req->req.length; + completed = 1; + /* There are still packets to transfer */ + } else if ( ep->dma_con) { + DMSG("%s: more packets,length:%d,actual:%d\n", + __FUNCTION__,req->req.length, + req->req.actual); + req->req.actual += ep->usb_ep->maxpacket; + completed = 0; + } else { + DMSG("%s: no more packets,length:%d," + "actual:%d\n", __FUNCTION__, + req->req.length, req->req.actual); + req->req.actual = req->req.length; + completed = 1; + } + } else { + req->req.actual = req->req.length; + completed = 1; + } + } else if (dcsr & DCSR_EORINTR) { //Only happened in OUT DMA + int remain,udccsr ; + + DCSR(dmach) = DCSR_EORINTR; + remain = DCMD(dmach) & DCMD_LENGTH; + req->req.actual = req->req.length - remain; + + udccsr = *ep->reg_udccsr; + if (udccsr & UDCCSR_SP) { + *ep->reg_udccsr = UDCCSR_PC | (udccsr & UDCCSR_MASK); + completed = 1; + } + DMSG("%s: length:%d actual:%d\n", + __FUNCTION__, req->req.length, req->req.actual); + } else + DMSG("%s: Others dma:%d DCSR:0x%x DCMD:0x%x\n", + __FUNCTION__, dmach, DCSR(dmach), DCMD(dmach)); + + if (likely(completed)) { + if (req->queue.next != &ep->queue) { + req_next = list_entry(req->queue.next, + struct pxa27x_request, queue); + kick_dma(ep, req_next); + } + done(ep, req, 0); + } else { + kick_dma(ep, req); + } + + local_irq_enable(); +} + +#endif +/*-------------------------------------------------------------------------*/ + +static int +pxa27x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) +{ + struct pxa27x_virt_ep *virt_ep; + struct pxa27x_ep *ep; + struct pxa27x_request *req; + struct pxa27x_udc *dev; + unsigned long flags; + + virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); + ep = virt_ep->pxa_ep; + + req = container_of(_req, struct pxa27x_request, req); + if (unlikely (!_req || !_req->complete || !_req->buf|| + !list_empty(&req->queue))) { + DMSG("%s, bad params\n", __FUNCTION__); + return -EINVAL; + } + + if (unlikely (!_ep || (!ep->desc && _ep->name != ep0name))) { + DMSG("%s, bad ep\n", __FUNCTION__); + return -EINVAL; + } + + DMSG("%s, ep point %d is queue\n", __FUNCTION__, ep->ep_num); + + dev = ep->dev; + if (unlikely (!dev->driver + || dev->gadget.speed == USB_SPEED_UNKNOWN)) { + DMSG("%s, bogus device state\n", __FUNCTION__); + return -ESHUTDOWN; + } + + /* iso is always one packet per request, that's the only way + * we can report per-packet status. that also helps with dma. + */ + if (unlikely (ep->ep_type == USB_ENDPOINT_XFER_ISOC + && req->req.length > le16_to_cpu + (ep->desc->wMaxPacketSize))) + return -EMSGSIZE; + +#ifdef USE_DMA + // FIXME caller may already have done the dma mapping + if (ep->dma >= 0) { + _req->dma = dma_map_single(dev->dev, _req->buf, _req->length, + (ep->dir_in) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + } +#endif + + DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n", + _ep->name, _req, _req->length, _req->buf); + + local_irq_save(flags); + + _req->status = -EINPROGRESS; + _req->actual = 0; + + /* kickstart this i/o queue? */ + if (list_empty(&ep->queue) && !ep->stopped) { + if (ep->desc == 0 /* ep0 */) { + unsigned length = _req->length; + + switch (dev->ep0state) { + case EP0_IN_DATA_PHASE: + dev->stats.write.ops++; + if (write_ep0_fifo(ep, req)) + req = 0; + break; + + case EP0_OUT_DATA_PHASE: + dev->stats.read.ops++; + if (dev->req_pending) + ep0start(dev, UDCCSR0_IPR, "OUT"); + if (length == 0 || ((UDCCSR0 & UDCCSR0_RNE) != 0 + && read_ep0_fifo(ep, req))) { + ep0_idle(dev); + done(ep, req, 0); + req = 0; + } + break; + case EP0_NO_ACTION: + ep0_idle(dev); + req=0; + break; + default: + DMSG("ep0 i/o, odd state %d\n", dev->ep0state); + local_irq_restore (flags); + return -EL2HLT; + } +#ifdef USE_DMA + /* either start dma or prime pio pump */ + } else if (ep->dma >= 0) { + kick_dma(ep, req); +#endif + /* can the FIFO can satisfy the request immediately? */ + } else if (ep->dir_in && (*ep->reg_udccsr & UDCCSR_FS) != 0 + && write_fifo(ep, req)) { + req = 0; + } else if ((*ep->reg_udccsr & UDCCSR_FS) != 0 + && read_fifo(ep, req)) { + req = 0; + } + DMSG("req:%p,ep->desc:%p,ep->dma:%d\n", req, ep->desc, ep->dma); + if (likely (req && ep->desc) && ep->dma < 0) + pio_irq_enable(ep->pxa_ep_num); + } + + /* pio or dma irq handler advances the queue. */ + if (likely (req != 0)) + list_add_tail(&req->queue, &ep->queue); + local_irq_restore(flags); + + return 0; +} + + +/* + * nuke - dequeue ALL requests + */ +static void nuke(struct pxa27x_ep *ep, int status) +{ + struct pxa27x_request *req; + + /* called with irqs blocked */ +#ifdef USE_DMA + if (ep->dma >= 0 && !ep->stopped) + cancel_dma(ep); +#endif + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct pxa27x_request, queue); + done(ep, req, status); + } + if (ep->desc) + pio_irq_disable(ep->pxa_ep_num); +} + + +/* dequeue JUST ONE request */ +static int pxa27x_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct pxa27x_virt_ep *virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); + struct pxa27x_ep *ep = virt_ep->pxa_ep; + struct pxa27x_request *req; + unsigned long flags; + + if (!_ep || _ep->name == ep0name) + return -EINVAL; + + local_irq_save(flags); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + local_irq_restore(flags); + return -EINVAL; + } + +#ifdef USE_DMA + if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) { + cancel_dma(ep); + done(ep, req, -ECONNRESET); + /* restart i/o */ + if (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct pxa27x_request, queue); + kick_dma(ep, req); + } + } else +#endif + done(ep, req, -ECONNRESET); + + local_irq_restore(flags); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static int pxa27x_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct pxa27x_virt_ep *virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); + struct pxa27x_ep *ep = virt_ep->pxa_ep; + unsigned long flags; + + DMSG("%s is called\n", __FUNCTION__); + if (unlikely (!_ep || (!ep->desc && _ep->name != ep0name)) + || ep->ep_type == USB_ENDPOINT_XFER_ISOC) { + DMSG("%s, bad ep\n", __FUNCTION__); + return -EINVAL; + } + if (value == 0) { + /* this path (reset toggle+halt) is needed to implement + * SET_INTERFACE on normal hardware. but it can't be + * done from software on the PXA UDC, and the hardware + * forgets to do it as part of SET_INTERFACE automagic. + */ + DMSG("only host can clear %s halt\n", _ep->name); + return -EROFS; + } + + local_irq_save(flags); + + if (ep->dir_in && ((*ep->reg_udccsr & UDCCSR_FS) == 0 + || !list_empty(&ep->queue))) { + local_irq_restore(flags); + return -EAGAIN; + } + + /* FST bit is the same for control, bulk in, bulk out, interrupt in */ + *ep->reg_udccsr = UDCCSR_FST|UDCCSR_FEF; + + /* ep0 needs special care */ + if (!ep->desc) { + start_watchdog(ep->dev); + ep->dev->req_pending = 0; + ep->dev->ep0state = EP0_STALL; + + /* and bulk/intr endpoints like dropping stalls too */ + } else { + unsigned i; + for (i = 0; i < 1000; i += 20) { + if (*ep->reg_udccsr & UDCCSR_SST) + break; + udelay(20); + } + } + local_irq_restore(flags); + + DBG(DBG_VERBOSE, "%s halt\n", _ep->name); + return 0; +} + +static int pxa27x_ep_fifo_status(struct usb_ep *_ep) +{ + struct pxa27x_virt_ep *virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); + struct pxa27x_ep *ep = virt_ep->pxa_ep; + + if (!_ep) { + DMSG("%s, bad ep\n", __FUNCTION__); + return -ENODEV; + } + /* pxa can't report unclaimed bytes from IN fifos */ + if (ep->dir_in) + return -EOPNOTSUPP; + if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN + || (*ep->reg_udccsr & UDCCSR_FS) == 0) + return 0; + else + return (*ep->reg_udcbcr & 0xfff) + 1; +} + +static void pxa27x_ep_fifo_flush(struct usb_ep *_ep) +{ + struct pxa27x_virt_ep *virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); + struct pxa27x_ep *ep = virt_ep->pxa_ep; + + DMSG("pxa27x_ep_fifo_flush\n"); + + if (!_ep || _ep->name == ep0name || !list_empty(&ep->queue)) { + DMSG("%s, bad ep\n", __FUNCTION__); + return; + } + + /* toggle and halt bits stay unchanged */ + + /* for OUT, just read and discard the FIFO contents. */ + if (!ep->dir_in) { + while (((*ep->reg_udccsr) & UDCCSR_BNE) != 0) + (void) *ep->reg_udcdr; + return; + } + + /* most IN status is the same, but ISO can't stall */ + *ep->reg_udccsr = UDCCSR_PC|UDCCSR_FST|UDCCSR_TRN + | (ep->ep_type == USB_ENDPOINT_XFER_ISOC) + ? 0 : UDCCSR_SST; +} + + +static struct usb_ep_ops pxa27x_ep_ops = { + .enable = pxa27x_ep_enable, + .disable = pxa27x_ep_disable, + + .alloc_request = pxa27x_ep_alloc_request, + .free_request = pxa27x_ep_free_request, + + .alloc_buffer = pxa27x_ep_alloc_buffer, + .free_buffer = pxa27x_ep_free_buffer, + + .queue = pxa27x_ep_queue, + .dequeue = pxa27x_ep_dequeue, + + .set_halt = pxa27x_ep_set_halt, + .fifo_status = pxa27x_ep_fifo_status, + .fifo_flush = pxa27x_ep_fifo_flush, +}; + + +/* --------------------------------------------------------------------------- + * device-scoped parts of the api to the usb controller hardware + * --------------------------------------------------------------------------- + */ + +static inline unsigned int validate_fifo_size(u8 bmAttributes) +{ + switch (bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + return EP0_FIFO_SIZE; + break; + case USB_ENDPOINT_XFER_ISOC: + return ISO_FIFO_SIZE; + break; + case USB_ENDPOINT_XFER_BULK: + return BULK_FIFO_SIZE; + break; + case USB_ENDPOINT_XFER_INT: + return INT_FIFO_SIZE; + break; + default: + break; + } +} + +static void pxa27x_ep_free(struct usb_gadget *gadget, struct usb_ep *_ep) +{ + struct pxa27x_udc *dev = the_controller; + struct pxa27x_virt_ep *virt_ep; + int i; + + virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); + + for (i = 1; i < UDC_EP_NUM; i++) { + if (dev->ep[i].usb_ep == &virt_ep->usb_ep) { + if (dev->ep[i].desc) { + virt_ep->pxa_ep = &dev->ep[i]; + pxa27x_ep_disable(&virt_ep->usb_ep); + } + dev->ep[i].usb_ep = NULL; + } + } + + if (!list_empty(&virt_ep->usb_ep.ep_list)) + list_del_init(&virt_ep->usb_ep.ep_list); + + kfree(virt_ep->usb_ep.name); + kfree(virt_ep); +} + +static void pxa27x_ep_freeall(struct usb_gadget *gadget) +{ + struct pxa27x_udc *dev = the_controller; + int i; + + for (i = 1; i < UDC_EP_NUM; i++) { + if(dev->ep[i].usb_ep) + pxa27x_ep_free(gadget, dev->ep[i].usb_ep); + } +} + +#define NAME_SIZE 18 + +static int pxa27x_find_free_ep(struct pxa27x_udc *dev) +{ + int i; + for (i = 1; i < UDC_EP_NUM; i++) { + if(!dev->ep[i].assigned) + return i; + } + return -1; +} + +/* + * Endpoint Allocation/Configuration + * + * pxa27x endpoint configuration is fixed when the device is enabled. Any pxa + * endpoint is only active in one configuration, interface and alternate + * interface combination so to support gadget drivers, we map one usb_ep to + * one of several pxa ep's. One pxa endpoint is assigned per configuration + * combination. + */ +static struct usb_ep* pxa27x_ep_alloc(struct usb_gadget *gadget, struct usb_endpoint_descriptor *desc, + struct usb_endpoint_config *epconfig, int configs) +{ + struct pxa27x_udc *dev = the_controller; + struct pxa27x_virt_ep *virt_ep; + unsigned int i, fifo_size; + char *name; + + if (unlikely(configs < 1)) { + dev_err(dev->dev, "%s: Error in config data\n", __FUNCTION__); + return NULL; + } + + virt_ep = kmalloc(sizeof(struct pxa27x_virt_ep), GFP_KERNEL); + name = kmalloc(NAME_SIZE, GFP_KERNEL); + if (!virt_ep || !name) { + dev_err(dev->dev, "%s: -ENOMEM\n", __FUNCTION__); + kfree(name); + kfree(virt_ep); + return NULL; + } + + if (!(desc->wMaxPacketSize)) { + fifo_size = validate_fifo_size(desc->bmAttributes); + desc->wMaxPacketSize = fifo_size; + } else { + fifo_size = desc->wMaxPacketSize; + } + + DMSG("pxa27x_ep_alloc: bLength: %d, bDescriptorType: %x, bEndpointAddress: %x,\n" + " bmAttributes: %x, wMaxPacketSize: %d\n", desc->bLength, + desc->bDescriptorType, desc->bEndpointAddress, desc->bmAttributes, + desc->wMaxPacketSize); + + if (!(desc->bEndpointAddress & 0xF)) + desc->bEndpointAddress |= dev->ep_num; + + for (i = 0; i < configs; i++) + { + struct pxa27x_ep *pxa_ep; + int j; + + DMSG("pxa27x_ep_alloc: config: %d, interface: %d, altinterface: %x,\n", + epconfig->config, epconfig->interface, epconfig->altinterface); + + j = pxa27x_find_free_ep(dev); + + if (unlikely(j < 0)) { + dev_err(dev->dev, "pxa27x_ep_alloc: Failed to find a spare endpoint\n"); + pxa27x_ep_free(gadget, &virt_ep->usb_ep); + return NULL; + } + + pxa_ep = &dev->ep[j]; + + if (i == 0) + virt_ep->pxa_ep = pxa_ep; + + pxa_ep->assigned = 1; + pxa_ep->ep_num = dev->ep_num; + pxa_ep->pxa_ep_num = j; + pxa_ep->usb_ep = &virt_ep->usb_ep; + pxa_ep->dev = dev; + pxa_ep->desc = desc; + pxa_ep->pio_irqs = pxa_ep->dma_irqs = 0; + pxa_ep->dma = -1; + + pxa_ep->fifo_size = fifo_size; + pxa_ep->dir_in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0; + pxa_ep->ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + pxa_ep->stopped = 1; + pxa_ep->dma_con = 0; + pxa_ep->config = epconfig->config; + pxa_ep->interface = epconfig->interface; + pxa_ep->aisn = epconfig->altinterface; + + pxa_ep->reg_udccsr = &UDCCSR0 + j; + pxa_ep->reg_udcbcr = &UDCBCR0 + j; + pxa_ep->reg_udcdr = &UDCDR0 + j ; + pxa_ep->reg_udccr = &UDCCRA - 1 + j; +#ifdef USE_DMA + pxa_ep->reg_drcmr = &DRCMR24 + j; +#endif + + /* Configure UDCCR */ + *pxa_ep->reg_udccr = ((pxa_ep->config << UDCCONR_CN_S) & UDCCONR_CN) + | ((pxa_ep->interface << UDCCONR_IN_S) & UDCCONR_IN) + | ((pxa_ep->aisn << UDCCONR_AISN_S) & UDCCONR_AISN) + | ((dev->ep_num << UDCCONR_EN_S) & UDCCONR_EN) + | ((pxa_ep->ep_type << UDCCONR_ET_S) & UDCCONR_ET) + | ((pxa_ep->dir_in) ? UDCCONR_ED : 0) + | ((min(pxa_ep->fifo_size, (unsigned)desc->wMaxPacketSize) << UDCCONR_MPS_S ) & UDCCONR_MPS) + | UDCCONR_EE; +// | UDCCONR_DE | UDCCONR_EE; + + + +#ifdef USE_DMA + /* Only BULK use DMA */ + if ((pxa_ep->ep_type & USB_ENDPOINT_XFERTYPE_MASK)\ + == USB_ENDPOINT_XFER_BULK) + *pxa_ep->reg_udccsr = UDCCSR_DME; +#endif + + DMSG("UDCCR: 0x%p is 0x%x\n", pxa_ep->reg_udccr,*pxa_ep->reg_udccr); + + epconfig++; + } + + /* Fill ep name*/ + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_BULK: + sprintf(name, "ep%d%s-bulk", dev->ep_num, + ((desc->bEndpointAddress & USB_DIR_IN) ? "in":"out")); + break; + case USB_ENDPOINT_XFER_INT: + sprintf(name, "ep%d%s-intr", dev->ep_num, + ((desc->bEndpointAddress & USB_DIR_IN) ? "in":"out")); + break; + default: + sprintf(name, "ep%d%s", dev->ep_num, + ((desc->bEndpointAddress & USB_DIR_IN) ? "in":"out")); + break; + } + + virt_ep->desc = desc; + virt_ep->usb_ep.name = name; + virt_ep->usb_ep.ops = &pxa27x_ep_ops; + virt_ep->usb_ep.maxpacket = min((ushort)fifo_size, desc->wMaxPacketSize); + + list_add_tail(&virt_ep->usb_ep.ep_list, &gadget->ep_list); + + dev->ep_num++; + return &virt_ep->usb_ep; +} + +static int pxa27x_udc_get_frame(struct usb_gadget *_gadget) +{ + return (UDCFNR & 0x7FF); +} + +static int pxa27x_udc_wakeup(struct usb_gadget *_gadget) +{ + /* host may not have enabled remote wakeup */ + if ((UDCCR & UDCCR_DWRE) == 0) + return -EHOSTUNREACH; + udc_set_mask_UDCCR(UDCCR_UDR); + return 0; +} + +static const struct usb_gadget_ops pxa27x_udc_ops = { + .ep_alloc = pxa27x_ep_alloc, + .get_frame = pxa27x_udc_get_frame, + .wakeup = pxa27x_udc_wakeup, + // current versions must always be self-powered +}; + + +/*-------------------------------------------------------------------------*/ + +#ifdef UDC_PROC_FILE + +static const char proc_node_name [] = "driver/udc"; + +static int +udc_proc_read(char *page, char **start, off_t off, int count, + int *eof, void *_dev) +{ + char *buf = page; + struct pxa27x_udc *dev = _dev; + char *next = buf; + unsigned size = count; + unsigned long flags; + int i, t; + u32 tmp; + + if (off != 0) + return 0; + + local_irq_save(flags); + + /* basic device status */ + t = scnprintf(next, size, DRIVER_DESC "\n" + "%s version: %s\nGadget driver: %s\n", + driver_name, DRIVER_VERSION SIZE_STR DMASTR, + dev->driver ? dev->driver->driver.name : "(none)"); + size -= t; + next += t; + + /* registers for device and ep0 */ + t = scnprintf(next, size, + "uicr %02X.%02X, usir %02X.%02x, ufnr %02X\n", + UDCICR1, UDCICR0, UDCISR1, UDCISR0, UDCFNR); + size -= t; + next += t; + + tmp = UDCCR; + t = scnprintf(next, size,"udccr %02X =%s%s%s%s%s%s%s%s%s%s, con=%d,inter=%d,altinter=%d\n", tmp, + (tmp & UDCCR_OEN) ? " oen":"", + (tmp & UDCCR_AALTHNP) ? " aalthnp":"", + (tmp & UDCCR_AHNP) ? " rem" : "", + (tmp & UDCCR_BHNP) ? " rstir" : "", + (tmp & UDCCR_DWRE) ? " dwre" : "", + (tmp & UDCCR_SMAC) ? " smac" : "", + (tmp & UDCCR_EMCE) ? " emce" : "", + (tmp & UDCCR_UDR) ? " udr" : "", + (tmp & UDCCR_UDA) ? " uda" : "", + (tmp & UDCCR_UDE) ? " ude" : "", + (tmp & UDCCR_ACN) >> UDCCR_ACN_S, + (tmp & UDCCR_AIN) >> UDCCR_AIN_S, + (tmp & UDCCR_AAISN)>> UDCCR_AAISN_S ); + + size -= t; + next += t; + + tmp = UDCCSR0; + t = scnprintf(next, size, + "udccsr0 %02X =%s%s%s%s%s%s%s\n", tmp, + (tmp & UDCCSR0_SA) ? " sa" : "", + (tmp & UDCCSR0_RNE) ? " rne" : "", + (tmp & UDCCSR0_FST) ? " fst" : "", + (tmp & UDCCSR0_SST) ? " sst" : "", + (tmp & UDCCSR0_DME) ? " dme" : "", + (tmp & UDCCSR0_IPR) ? " ipr" : "", + (tmp & UDCCSR0_OPC) ? " opc" : ""); + size -= t; + next += t; + + if (!dev->driver) + goto done; + + t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", + dev->stats.write.bytes, dev->stats.write.ops, + dev->stats.read.bytes, dev->stats.read.ops, + dev->stats.irqs); + size -= t; + next += t; + + /* dump endpoint queues */ + for (i = 0; i < UDC_EP_NUM; i++) { + struct pxa27x_ep *ep = &dev->ep [i]; + struct pxa27x_request *req; + int t; + + if (i != 0) { + const struct usb_endpoint_descriptor *d; + + d = ep->desc; + if (!d) + continue; + tmp = *dev->ep [i].reg_udccsr; + t = scnprintf(next, size, + "%d max %d %s udccs %02x udccr:0x%x\n", + i, le16_to_cpu (d->wMaxPacketSize), + (ep->dma >= 0) ? "dma" : "pio", tmp, + *dev->ep[i].reg_udccr); + /* TODO translate all five groups of udccs bits! */ + + } else /* ep0 should only have one transfer queued */ + t = scnprintf(next, size, "ep0 max 16 pio irqs %lu\n", + ep->pio_irqs); + if (t <= 0 || t > size) + goto done; + size -= t; + next += t; + + if (list_empty(&ep->queue)) { + t = scnprintf(next, size, "\t(nothing queued)\n"); + if (t <= 0 || t > size) + goto done; + size -= t; + next += t; + continue; + } + list_for_each_entry(req, &ep->queue, queue) { +#ifdef USE_DMA + if (ep->dma >= 0 && req->queue.prev == &ep->queue) + t = scnprintf(next, size, "\treq %p len %d/%d " + "buf %p (dma%d dcmd %08x)\n", + &req->req, req->req.actual, + req->req.length, req->req.buf, + ep->dma, DCMD(ep->dma) + /* low 13 bits == bytes-to-go */); + else +#endif + t = scnprintf(next, size, + "\treq %p len %d/%d buf %p\n", + &req->req, req->req.actual, + req->req.length, req->req.buf); + if (t <= 0 || t > size) + goto done; + size -= t; + next += t; + } + } + +done: + local_irq_restore(flags); + *eof = 1; + return count - size; +} + +#define create_proc_files() \ + create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev) +#define remove_proc_files() \ + remove_proc_entry(proc_node_name, NULL) + +#else /* !UDC_PROC_FILE */ +#define create_proc_files() do {} while (0) +#define remove_proc_files() do {} while (0) + +#endif /* UDC_PROC_FILE */ + +/* "function" sysfs attribute */ +static ssize_t show_function(struct device *_dev, struct device_attribute *attr, char *buf) +{ + struct pxa27x_udc *dev = dev_get_drvdata(_dev); + + if (!dev->driver || !dev->driver->function + || strlen(dev->driver->function) > PAGE_SIZE) + return 0; + return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function); +} +static DEVICE_ATTR(function, S_IRUGO, show_function, NULL); + +/*-------------------------------------------------------------------------*/ + +/* + * udc_disable - disable USB device controller + */ +static void udc_disable(struct pxa27x_udc *dev) +{ + UDCICR0 = UDCICR1 = 0x00000000; + + udc_clear_mask_UDCCR(UDCCR_UDE); + + /* Disable clock for USB device */ + pxa_set_cken(CKEN_USB, 0); + + ep0_idle(dev); + dev->gadget.speed = USB_SPEED_UNKNOWN; + if (dev->mach->gpio_pullup) + gpio_set_value(dev->mach->gpio_pullup, 0); + else if (dev->mach->udc_command) + dev->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); +} + + +/* + * udc_reinit - initialize software state + */ +static void udc_reinit(struct pxa27x_udc *dev) +{ + u32 i; + + dev->ep0state = EP0_IDLE; + + /* basic endpoint records init */ + for (i = 0; i < UDC_EP_NUM; i++) { + struct pxa27x_ep *ep = &dev->ep[i]; + + ep->stopped = 0; + ep->pio_irqs = ep->dma_irqs = 0; + } + dev->configuration = 0; + dev->interface = 0; + dev->alternate = 0; + /* the rest was statically initialized, and is read-only */ +} + +/* until it's enabled, this UDC should be completely invisible + * to any USB host. + */ +static void udc_enable(struct pxa27x_udc *dev) +{ + udc_clear_mask_UDCCR(UDCCR_UDE); + + /* Enable clock for USB device */ + pxa_set_cken(CKEN_USB, 1); + + UDCICR0 = UDCICR1 = 0; + + ep0_idle(dev); + dev->gadget.speed = USB_SPEED_FULL; + dev->stats.irqs = 0; + + udc_set_mask_UDCCR(UDCCR_UDE); + udelay(2); + if (UDCCR & UDCCR_EMCE) + dev_err(dev->dev, "There are error in configuration, udc disabled\n"); + + /* caller must be able to sleep in order to cope + * with startup transients. + */ + msleep(100); + + /* enable suspend/resume and reset irqs */ + UDCICR1 = UDCICR1_IECC | UDCICR1_IERU | UDCICR1_IESU | UDCICR1_IERS; + + /* enable ep0 irqs */ + UDCICR0 = UDCICR_INT(0,UDCICR_INT_MASK); + if (dev->mach->gpio_pullup) + gpio_set_value(dev->mach->gpio_pullup, 1); + else if (dev->mach->udc_command) + dev->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); +} + + +/* when a driver is successfully registered, it will receive + * control requests including set_configuration(), which enables + * non-control requests. then usb traffic follows until a + * disconnect is reported. then a host may connect again, or + * the driver might get unbound. + */ +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct pxa27x_udc *dev = the_controller; + int retval; + + if (!driver || driver->speed != USB_SPEED_FULL || !driver->bind + || !driver->unbind || !driver->disconnect || !driver->setup) + return -EINVAL; + if (!dev) + return -ENODEV; + if (dev->driver) + return -EBUSY; + + udc_disable(dev); + udc_init_ep(dev); + udc_reinit(dev); + + /* first hook up the driver ... */ + dev->driver = driver; + dev->gadget.dev.driver = &driver->driver; + dev->ep_num = 1; + + retval = device_add(&dev->gadget.dev); + if (retval) { + DMSG("device_add error %d\n", retval); + goto add_fail; + } + retval = driver->bind(&dev->gadget); + if (retval) { + DMSG("bind to driver %s --> error %d\n", + driver->driver.name, retval); + goto bind_fail; + } + retval = device_create_file(dev->dev, &dev_attr_function); + if (retval) { + DMSG("device_create_file failed: %d\n", retval); + goto create_file_fail; + } + + /* ... then enable host detection and ep0; and we're ready + * for set_configuration as well as eventual disconnect. + * NOTE: this shouldn't power up until later. + */ + DMSG("registered gadget driver '%s'\n", driver->driver.name); + udc_enable(dev); + dump_state(dev); + return 0; + +create_file_fail: + driver->unbind(&dev->gadget); +bind_fail: + device_del(&dev->gadget.dev); +add_fail: + dev->driver = 0; + dev->gadget.dev.driver = 0; + return retval; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +static void +stop_activity(struct pxa27x_udc *dev, struct usb_gadget_driver *driver) +{ + int i; + + DMSG("Trace path 1\n"); + /* don't disconnect drivers more than once */ + if (dev->gadget.speed == USB_SPEED_UNKNOWN) + driver = 0; + dev->gadget.speed = USB_SPEED_UNKNOWN; + + /* prevent new request submissions, kill any outstanding requests */ + for (i = 0; i < UDC_EP_NUM; i++) { + struct pxa27x_ep *ep = &dev->ep[i]; + + ep->stopped = 1; + nuke(ep, -ESHUTDOWN); + } + del_timer_sync(&dev->timer); + + /* report disconnect; the driver is already quiesced */ + if (driver) + driver->disconnect(&dev->gadget); + + /* re-init driver-visible data structures */ + udc_reinit(dev); +} + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct pxa27x_udc *dev = the_controller; + + if (!dev) + return -ENODEV; + if (!driver || driver != dev->driver) + return -EINVAL; + + local_irq_disable(); + udc_disable(dev); + stop_activity(dev, driver); + local_irq_enable(); + + driver->unbind(&dev->gadget); + pxa27x_ep_freeall(&dev->gadget); + dev->driver = 0; + + device_del(&dev->gadget.dev); + device_remove_file(dev->dev, &dev_attr_function); + + DMSG("unregistered gadget driver '%s'\n", driver->driver.name); + dump_state(dev); + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + + +/*-------------------------------------------------------------------------*/ + +static inline void clear_ep_state(struct pxa27x_udc *dev) +{ + unsigned i; + + /* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint + * fifos, and pending transactions mustn't be continued in any case. + */ + for (i = 1; i < UDC_EP_NUM; i++) + nuke(&dev->ep[i], -ECONNABORTED); +} + +static void udc_watchdog(unsigned long _dev) +{ + struct pxa27x_udc *dev = (void *)_dev; + + local_irq_disable(); + if (dev->ep0state == EP0_STALL + && (UDCCSR0 & UDCCSR0_FST) == 0 + && (UDCCSR0 & UDCCSR0_SST) == 0) { + UDCCSR0 = UDCCSR0_FST|UDCCSR0_FTF; + DBG(DBG_VERBOSE, "ep0 re-stall\n"); + start_watchdog(dev); + } + local_irq_enable(); +} + +static void handle_ep0(struct pxa27x_udc *dev) +{ + u32 udccsr0 = UDCCSR0; + struct pxa27x_ep *ep = &dev->ep[0]; + struct pxa27x_request *req; + union { + struct usb_ctrlrequest r; + u8 raw[8]; + u32 word[2]; + } u; + + if (list_empty(&ep->queue)) + req = 0; + else + req = list_entry(ep->queue.next, struct pxa27x_request, queue); + + /* clear stall status */ + if (udccsr0 & UDCCSR0_SST) { + nuke(ep, -EPIPE); + UDCCSR0 = UDCCSR0_SST; + del_timer(&dev->timer); + ep0_idle(dev); + } + + /* previous request unfinished? non-error iff back-to-back ... */ + if ((udccsr0 & UDCCSR0_SA) != 0 && dev->ep0state != EP0_IDLE) { + nuke(ep, 0); + del_timer(&dev->timer); + ep0_idle(dev); + } + + switch (dev->ep0state) { + case EP0_NO_ACTION: + dev_info(dev->dev, "%s: Busy\n", __FUNCTION__); + /*Fall through */ + case EP0_IDLE: + /* late-breaking status? */ + udccsr0 = UDCCSR0; + + /* start control request? */ + if (likely((udccsr0 & (UDCCSR0_OPC|UDCCSR0_SA|UDCCSR0_RNE)) + == (UDCCSR0_OPC|UDCCSR0_SA|UDCCSR0_RNE))) { + int i; + + nuke(ep, -EPROTO); + /* read SETUP packet */ + for (i = 0; i < 2; i++) { + if (unlikely(!(UDCCSR0 & UDCCSR0_RNE))) { +bad_setup: + DMSG("SETUP %d!\n", i); + goto stall; + } + u.word [i] = UDCDR0; + } + if (unlikely((UDCCSR0 & UDCCSR0_RNE) != 0)) + goto bad_setup; + + le16_to_cpus(&u.r.wValue); + le16_to_cpus(&u.r.wIndex); + le16_to_cpus(&u.r.wLength); + + DBG(DBG_VERBOSE, "SETUP %02x.%02x v%04x i%04x l%04x\n", + u.r.bRequestType, u.r.bRequest, + u.r.wValue, u.r.wIndex, u.r.wLength); + /* cope with automagic for some standard requests. */ + dev->req_std = (u.r.bRequestType & USB_TYPE_MASK) + == USB_TYPE_STANDARD; + dev->req_config = 0; + dev->req_pending = 1; +#if 0 + switch (u.r.bRequest) { + /* hardware was supposed to hide this */ + case USB_REQ_SET_CONFIGURATION: + case USB_REQ_SET_INTERFACE: + case USB_REQ_SET_ADDRESS: + dev_err(dev->dev, "Should not come here\n"); + break; + } + +#endif + if (u.r.bRequestType & USB_DIR_IN) + dev->ep0state = EP0_IN_DATA_PHASE; + else + dev->ep0state = EP0_OUT_DATA_PHASE; + i = dev->driver->setup(&dev->gadget, &u.r); + + if (i < 0) { + /* hardware automagic preventing STALL... */ + if (dev->req_config) { + /* hardware sometimes neglects to tell + * tell us about config change events, + * so later ones may fail... + */ + WARN("config change %02x fail %d?\n", + u.r.bRequest, i); + return; + /* TODO experiment: if has_cfr, + * hardware didn't ACK; maybe we + * could actually STALL! + */ + } + DBG(DBG_VERBOSE, "protocol STALL, " + "%02x err %d\n", UDCCSR0, i); +stall: + /* the watchdog timer helps deal with cases + * where udc seems to clear FST wrongly, and + * then NAKs instead of STALLing. + */ + ep0start(dev, UDCCSR0_FST|UDCCSR0_FTF, "stall"); + start_watchdog(dev); + dev->ep0state = EP0_STALL; + + /* deferred i/o == no response yet */ + } else if (dev->req_pending) { + if (likely(dev->ep0state == EP0_IN_DATA_PHASE + || dev->req_std || u.r.wLength)) + ep0start(dev, 0, "defer"); + else + ep0start(dev, UDCCSR0_IPR, "defer/IPR"); + } + + /* expect at least one data or status stage irq */ + return; + + } else { + /* some random early IRQ: + * - we acked FST + * - IPR cleared + * - OPC got set, without SA (likely status stage) + */ + UDCCSR0 = udccsr0 & (UDCCSR0_SA|UDCCSR0_OPC); + } + break; + case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ + if (udccsr0 & UDCCSR0_OPC) { + UDCCSR0 = UDCCSR0_OPC|UDCCSR0_FTF; + DBG(DBG_VERBOSE, "ep0in premature status\n"); + if (req) + done(ep, req, 0); + ep0_idle(dev); + } else /* irq was IPR clearing */ { + if (req) { + /* this IN packet might finish the request */ + (void) write_ep0_fifo(ep, req); + } /* else IN token before response was written */ + } + break; + case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ + if (udccsr0 & UDCCSR0_OPC) { + if (req) { + /* this OUT packet might finish the request */ + if (read_ep0_fifo(ep, req)) + done(ep, req, 0); + /* else more OUT packets expected */ + } /* else OUT token before read was issued */ + } else /* irq was IPR clearing */ { + DBG(DBG_VERBOSE, "ep0out premature status\n"); + if (req) + done(ep, req, 0); + ep0_idle(dev); + } + break; + case EP0_STALL: + UDCCSR0 = UDCCSR0_FST; + break; + } + UDCISR0 = UDCISR_INT(0, UDCISR_INT_MASK); +} + + +static void handle_ep(struct pxa27x_ep *ep) +{ + struct pxa27x_request *req; + int completed; + u32 udccsr=0; + + DMSG("%s is called\n", __FUNCTION__); + do { + completed = 0; + if (likely (!list_empty(&ep->queue))) { + req = list_entry(ep->queue.next, + struct pxa27x_request, queue); + } else + req = 0; + +// udccsr = *ep->reg_udccsr; + DMSG("%s: req:%p, udcisr0:0x%x udccsr %p:0x%x\n", __FUNCTION__, + req, UDCISR0, ep->reg_udccsr, *ep->reg_udccsr); + if (unlikely(ep->dir_in)) { + udccsr = (UDCCSR_SST | UDCCSR_TRN) & *ep->reg_udccsr; + if (unlikely (udccsr)) + *ep->reg_udccsr = udccsr; + + if (req && likely ((*ep->reg_udccsr & UDCCSR_FS) != 0)) + completed = write_fifo(ep, req); + + } else { + udccsr = (UDCCSR_SST | UDCCSR_TRN) & *ep->reg_udccsr; + if (unlikely(udccsr)) + *ep->reg_udccsr = udccsr; + + /* fifos can hold packets, ready for reading... */ + if (likely(req)) { + completed = read_fifo(ep, req); + } else { + pio_irq_disable (ep->pxa_ep_num); + *ep->reg_udccsr = UDCCSR_FEF; + DMSG("%s: no req for out data\n", + __FUNCTION__); + } + } + ep->pio_irqs++; + } while (completed); +} + +static void pxa27x_update_eps(struct pxa27x_udc *dev) +{ + struct pxa27x_virt_ep *virt_ep; + int i; + + for (i = 1; i < UDC_EP_NUM; i++) { + if(!dev->ep[i].assigned || !dev->ep[i].usb_ep) + continue; + virt_ep = container_of(dev->ep[i].usb_ep, struct pxa27x_virt_ep, usb_ep); + + DMSG("%s, Updating eps %d:%d, %d:%d, %d:%d, %p,%p\n", __FUNCTION__, dev->ep[i].config, dev->configuration + ,dev->ep[i].interface, dev->interface, dev->ep[i].aisn, dev->alternate, virt_ep->pxa_ep, &dev->ep[i]); + + if(dev->ep[i].config == dev->configuration && virt_ep->pxa_ep != &dev->ep[i]) { + if ((dev->ep[i].interface == dev->interface && + dev->ep[i].aisn == dev->alternate) || virt_ep->pxa_ep->config != dev->configuration) { + + if (virt_ep->pxa_ep->desc) { + DMSG("%s, Changing end point to %d (en/dis)\n", __FUNCTION__, i); + pxa27x_ep_disable(&virt_ep->usb_ep); + virt_ep->pxa_ep = &dev->ep[i]; + pxa27x_ep_enable(&virt_ep->usb_ep, virt_ep->desc); + } else { + DMSG("%s, Changing end point to %d (no en/dis)\n", __FUNCTION__, i); + virt_ep->pxa_ep = &dev->ep[i]; + } + } + } + } +} + +static void pxa27x_change_configuration(struct pxa27x_udc *dev) +{ + struct usb_ctrlrequest req ; + + pxa27x_update_eps(dev); + + req.bRequestType = 0; + req.bRequest = USB_REQ_SET_CONFIGURATION; + req.wValue = dev->configuration; + req.wIndex = 0; + req.wLength = 0; + + dev->ep0state = EP0_NO_ACTION; + dev->driver->setup(&dev->gadget, &req); +} + +static void pxa27x_change_interface(struct pxa27x_udc *dev) +{ + struct usb_ctrlrequest req; + + pxa27x_update_eps(dev); + + req.bRequestType = USB_RECIP_INTERFACE; + req.bRequest = USB_REQ_SET_INTERFACE; + req.wValue = dev->alternate; + req.wIndex = dev->interface; + req.wLength = 0; + + dev->ep0state = EP0_NO_ACTION; + dev->driver->setup(&dev->gadget, &req); +} + +/* + * pxa27x_udc_irq - interrupt handler + * + * avoid delays in ep0 processing. the control handshaking isn't always + * under software control (pxa250c0 and the pxa255 are better), and delays + * could cause usb protocol errors. + */ +static irqreturn_t pxa27x_udc_irq(int irq, void *_dev) +{ + struct pxa27x_udc *dev = _dev; + int handled; + + dev->stats.irqs++; + + DBG(DBG_VERBOSE, "Interrupt, UDCISR0:0x%08x, UDCISR1:0x%08x, " + "UDCCR:0x%08x\n", UDCISR0, UDCISR1, UDCCR); + do { + u32 udcir = UDCISR1 & 0xF8000000; + + handled = 0; + + /* SUSpend Interrupt Request */ + if (unlikely(udcir & UDCISR1_IRSU)) { + UDCISR1 = UDCISR1_IRSU; + handled = 1; + DBG(DBG_VERBOSE, "USB suspend\n"); + if (dev->gadget.speed != USB_SPEED_UNKNOWN + && dev->driver + && dev->driver->suspend) + dev->driver->suspend(&dev->gadget); + ep0_idle(dev); + } + + /* RESume Interrupt Request */ + if (unlikely(udcir & UDCISR1_IRRU)) { + UDCISR1 = UDCISR1_IRRU; + handled = 1; + DBG(DBG_VERBOSE, "USB resume\n"); + + if (dev->gadget.speed != USB_SPEED_UNKNOWN + && dev->driver + && dev->driver->resume) + dev->driver->resume(&dev->gadget); + } + + if (unlikely(udcir & UDCISR1_IRCC)) { + unsigned config, interface, alternate; + + handled = 1; + DBG(DBG_VERBOSE, "USB SET_CONFIGURATION or " + "SET_INTERFACE command received\n"); + + config = (UDCCR & UDCCR_ACN) >> UDCCR_ACN_S; + + if (dev->configuration != config) { + dev->configuration = config; + pxa27x_change_configuration(dev) ; + } + + interface = (UDCCR & UDCCR_AIN) >> UDCCR_AIN_S; + alternate = (UDCCR & UDCCR_AAISN) >> UDCCR_AAISN_S; + + if ((dev->interface != interface) || (dev->alternate != alternate)) { + dev->interface = interface; + dev->alternate = alternate; + pxa27x_change_interface(dev); + } + + UDCCR |= UDCCR_SMAC; + + UDCISR1 = UDCISR1_IRCC; + DMSG("%s: con:%d,inter:%d,alt:%d\n", + __FUNCTION__, config,interface, alternate); + } + + /* ReSeT Interrupt Request - USB reset */ + if (unlikely(udcir & UDCISR1_IRRS)) { + UDCISR1 = UDCISR1_IRRS; + handled = 1; + + if ((UDCCR & UDCCR_UDA) == 0) { + DBG(DBG_VERBOSE, "USB reset start\n"); + + /* reset driver and endpoints, + * in case that's not yet done + */ + stop_activity(dev, dev->driver); + } + INFO("USB reset\n"); + dev->gadget.speed = USB_SPEED_FULL; + memset(&dev->stats, 0, sizeof dev->stats); + + } else { + u32 udcisr0 = UDCISR0 ; + u32 udcisr1 = UDCISR1 & 0xFFFF; + int i; + + if (unlikely (!udcisr0 && !udcisr1)) + continue; + + DBG(DBG_VERY_NOISY, "irq %02x.%02x\n", udcisr1,udcisr0); + + /* control traffic */ + if (udcisr0 & UDCISR0_IR0) { + dev->ep[0].pio_irqs++; + handle_ep0(dev); + handled = 1; + } + + udcisr0 >>= 2; + /* endpoint data transfers */ + for (i = 1; udcisr0!=0 && i < 16; udcisr0>>=2,i++) { + UDCISR0 = UDCISR_INT(i, UDCISR_INT_MASK); + + if (udcisr0 & UDC_INT_FIFOERROR) + dev_err(dev->dev, " Endpoint %d Fifo error\n", i); + if (udcisr0 & UDC_INT_PACKETCMP) { + handle_ep(&dev->ep[i]); + handled = 1; + } + + } + + for (i = 0; udcisr1!=0 && i < 8; udcisr1 >>= 2, i++) { + UDCISR1 = UDCISR_INT(i, UDCISR_INT_MASK); + + if (udcisr1 & UDC_INT_FIFOERROR) { + dev_err(dev->dev, "Endpoint %d fifo error\n", (i+16)); + } + + if (udcisr1 & UDC_INT_PACKETCMP) { + handle_ep(&dev->ep[i+16]); + handled = 1; + } + } + } + + /* we could also ask for 1 msec SOF (SIR) interrupts */ + + } while (handled); + return IRQ_HANDLED; +} + +int write_ep0_zlp(void) +{ + UDCCSR0 = UDCCSR0_IPR; + return 0; +} +EXPORT_SYMBOL(write_ep0_zlp); + +static void udc_init_ep(struct pxa27x_udc *dev) +{ + int i; + + INIT_LIST_HEAD(&dev->gadget.ep_list); + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); + + for (i = 0; i < UDC_EP_NUM; i++) { + struct pxa27x_ep *ep = &dev->ep[i]; + + ep->dma = -1; + if (i != 0) { + memset(ep, 0, sizeof(*ep)); + } + INIT_LIST_HEAD(&ep->queue); + } +} + +/*-------------------------------------------------------------------------*/ + +static void nop_release(struct device *dev) +{ + DMSG("%s %s\n", __FUNCTION__, dev->bus_id); +} + +/* this uses load-time allocation and initialization (instead of + * doing it at run-time) to save code, eliminate fault paths, and + * be more obviously correct. + */ + +static struct pxa27x_udc memory = { + .gadget = { + .ops = &pxa27x_udc_ops, + .ep0 = &memory.virt_ep0.usb_ep, + .name = driver_name, + .dev = { + .bus_id = "gadget", + .release = nop_release, + }, + }, + + /* control endpoint */ + .virt_ep0 = { + .pxa_ep = &memory.ep[0], + .usb_ep = { + .name = ep0name, + .ops = &pxa27x_ep_ops, + .maxpacket = EP0_FIFO_SIZE, + }, + }, + + .ep[0] = { + .usb_ep = &memory.virt_ep0.usb_ep, + .dev = &memory, + .reg_udccsr = &UDCCSR0, + .reg_udcdr = &UDCDR0, + }, +}; + +#define CP15R0_VENDOR_MASK 0xffffe000 +#define CP15R0_XSCALE_VALUE 0x69054000 /* intel/arm/xscale */ + +static int __init pxa27x_udc_probe(struct platform_device *_dev) +{ + struct pxa27x_udc *dev = &memory; + int retval; + u32 chiprev; + + /* insist on Intel/ARM/XScale */ + asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev)); + if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) { + printk(KERN_ERR "%s: not XScale!\n", driver_name); + return -ENODEV; + } + /* other non-static parts of init */ + dev->dev = &_dev->dev; + dev->mach = _dev->dev.platform_data; + + init_timer(&dev->timer); + dev->timer.function = udc_watchdog; + dev->timer.data = (unsigned long) dev; + + device_initialize(&dev->gadget.dev); + dev->gadget.dev.parent = &_dev->dev; + dev->gadget.dev.dma_mask = _dev->dev.dma_mask; + + the_controller = dev; + platform_set_drvdata(_dev, dev); + + udc_disable(dev); + udc_init_ep(dev); + udc_reinit(dev); + + /* irq setup after old hardware state is cleaned up */ + retval = request_irq(IRQ_USB, pxa27x_udc_irq, + 0, driver_name, dev); + if (retval != 0) { + dev_err(dev->dev, "%s: can't get irq %i, err %d\n", + driver_name, IRQ_USB, retval); + return -EBUSY; + } + dev->got_irq = 1; + + create_proc_files(); + + return 0; +} + +static int __exit pxa27x_udc_remove(struct platform_device *_dev) +{ + struct pxa27x_udc *dev = platform_get_drvdata(_dev); + + udc_disable(dev); + remove_proc_files(); + usb_gadget_unregister_driver(dev->driver); + + pxa27x_ep_freeall(&dev->gadget); + + if (dev->got_irq) { + free_irq(IRQ_USB, dev); + dev->got_irq = 0; + } + platform_set_drvdata(_dev, 0); + the_controller = 0; + return 0; +} + +#ifdef CONFIG_PM +static void pxa27x_udc_shutdown(struct platform_device *_dev) +{ + struct pxa27x_udc *dev = platform_get_drvdata(_dev); + + udc_disable(dev); +} + +static int pxa27x_udc_suspend(struct platform_device *_dev, pm_message_t state) +{ + int i; + struct pxa27x_udc *dev = platform_get_drvdata(_dev); + + DMSG("%s is called\n", __FUNCTION__); + + dev->udccsr0 = UDCCSR0; + for(i=1; (iep[i].assigned) { + struct pxa27x_ep *ep = &dev->ep[i]; + ep->udccsr_value = *ep->reg_udccsr; + ep->udccr_value = *ep->reg_udccr; + DMSG("EP%d, udccsr:0x%x, udccr:0x%x\n", + i, *ep->reg_udccsr, *ep->reg_udccr); + } + } + + udc_clear_mask_UDCCR(UDCCR_UDE); + pxa_set_cken(CKEN11_USB, 0); + + return 0; +} + +static int pxa27x_udc_resume(struct platform_device *_dev) +{ + int i; + struct pxa27x_udc *dev = platform_get_drvdata(_dev); + + DMSG("%s is called\n", __FUNCTION__); + UDCCSR0 = dev->udccsr0 & (UDCCSR0_FST | UDCCSR0_DME); + for (i=1; i < UDC_EP_NUM; i++) { + if (dev->ep[i].assigned) { + struct pxa27x_ep *ep = &dev->ep[i]; + *ep->reg_udccsr = ep->udccsr_value; + *ep->reg_udccr = ep->udccr_value; + DMSG("EP%d, udccsr:0x%x, udccr:0x%x\n", + i, *ep->reg_udccsr, *ep->reg_udccr); + } + } + + udc_enable(dev); + + /* OTGPH bit is set when sleep mode is entered. + * it indicates that OTG pad is retaining its state. + * Upon exit from sleep mode and before clearing OTGPH, + * Software must configure the USB OTG pad, UDC, and UHC + * to the state they were in before entering sleep mode.*/ + PSSR |= PSSR_OTGPH; + + return 0; +} +#endif + +/*-------------------------------------------------------------------------*/ + +static struct platform_driver udc_driver = { + .driver = { + .name = "pxa2xx-udc", + }, + .probe = pxa27x_udc_probe, + .remove = __exit_p(pxa27x_udc_remove), +#ifdef CONFIG_PM + .shutdown = pxa27x_udc_shutdown, + .suspend = pxa27x_udc_suspend, + .resume = pxa27x_udc_resume +#endif +}; + +static int __init udc_init(void) +{ + printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION); + return platform_driver_register(&udc_driver); +} +module_init(udc_init); + +static void __exit udc_exit(void) +{ + platform_driver_unregister(&udc_driver); +} +module_exit(udc_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell"); +MODULE_LICENSE("GPL"); diff -urN linux-2.6.24.2/drivers/usb/gadget/pxa27x_udc.h linux-2.6.24.2-vpac1/drivers/usb/gadget/pxa27x_udc.h --- linux-2.6.24.2/drivers/usb/gadget/pxa27x_udc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/pxa27x_udc.h 2008-02-22 13:52:46.000000000 +0100 @@ -0,0 +1,342 @@ +/* + * linux/drivers/usb/gadget/pxa27x_udc.h + * Intel PXA27x on-chip full speed USB device controller + * + * Copyright (C) 2003 Robert Schwebel , Pengutronix + * Copyright (C) 2003 David Brownell + * Copyright (C) 2004 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_USB_GADGET_PXA27X_H +#define __LINUX_USB_GADGET_PXA27X_H + +#include + +struct pxa27x_udc; + +struct pxa27x_ep { + struct usb_ep ep; + struct pxa27x_udc *dev; + struct usb_ep *usb_ep; + const struct usb_endpoint_descriptor *desc; + + struct list_head queue; + unsigned long pio_irqs; + unsigned long dma_irqs; + + int dma; + unsigned fifo_size; + unsigned ep_num; + unsigned pxa_ep_num; + unsigned ep_type; + + unsigned stopped : 1; + unsigned dma_con : 1; + unsigned dir_in : 1; + unsigned assigned : 1; + + unsigned config; + unsigned interface; + unsigned aisn; + /* UDCCSR = UDC Control/Status Register for this EP + * UBCR = UDC Byte Count Remaining (contents of OUT fifo) + * UDCDR = UDC Endpoint Data Register (the fifo) + * UDCCR = UDC Endpoint Configuration Registers + * DRCM = DMA Request Channel Map + */ + volatile u32 *reg_udccsr; + volatile u32 *reg_udcbcr; + volatile u32 *reg_udcdr; + volatile u32 *reg_udccr; +#ifdef USE_DMA + volatile u32 *reg_drcmr; +#define drcmr(n) .reg_drcmr = & DRCMR ## n , +#else +#define drcmr(n) +#endif + +#ifdef CONFIG_PM + unsigned udccsr_value; + unsigned udccr_value; +#endif +}; + +struct pxa27x_virt_ep { + struct usb_ep usb_ep; + const struct usb_endpoint_descriptor *desc; + struct pxa27x_ep *pxa_ep; +}; + +struct pxa27x_request { + struct usb_request req; + struct list_head queue; +}; + +enum ep0_state { + EP0_IDLE, + EP0_IN_DATA_PHASE, + EP0_OUT_DATA_PHASE, +// EP0_END_XFER, + EP0_STALL, + EP0_NO_ACTION +}; + +#define EP0_FIFO_SIZE ((unsigned)16) +#define BULK_FIFO_SIZE ((unsigned)64) +#define ISO_FIFO_SIZE ((unsigned)256) +#define INT_FIFO_SIZE ((unsigned)8) + +struct udc_stats { + struct ep0stats { + unsigned long ops; + unsigned long bytes; + } read, write; + unsigned long irqs; +}; + +#ifdef CONFIG_USB_PXA27X_SMALL +/* when memory's tight, SMALL config saves code+data. */ +//#undef USE_DMA +//#define UDC_EP_NUM 3 +#endif + +#ifndef UDC_EP_NUM +#define UDC_EP_NUM 24 +#endif + +struct pxa27x_udc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + + enum ep0_state ep0state; + struct udc_stats stats; + unsigned got_irq : 1, + got_disc : 1, + has_cfr : 1, + req_pending : 1, + req_std : 1, + req_config : 1; + +#define start_watchdog(dev) mod_timer(&dev->timer, jiffies + (HZ/200)) + struct timer_list timer; + + struct device *dev; + struct pxa2xx_udc_mach_info *mach; + u64 dma_mask; + struct pxa27x_virt_ep virt_ep0; + struct pxa27x_ep ep[UDC_EP_NUM]; + unsigned int ep_num; + + unsigned configuration, + interface, + alternate; +#ifdef CONFIG_PM + unsigned udccsr0; +#endif +}; + +/*-------------------------------------------------------------------------*/ +#if 0 +#ifdef DEBUG +#define HEX_DISPLAY(n) do { \ + if (machine_is_mainstone())\ + { MST_LEDDAT1 = (n); } \ + } while(0) + +#define HEX_DISPLAY1(n) HEX_DISPLAY(n) + +#define HEX_DISPLAY2(n) do { \ + if (machine_is_mainstone()) \ + { MST_LEDDAT2 = (n); } \ + } while(0) + +#endif /* DEBUG */ +#endif +/*-------------------------------------------------------------------------*/ + +/* LEDs are only for debug */ +#ifndef HEX_DISPLAY +#define HEX_DISPLAY(n) do {} while(0) +#endif + +#ifndef LED_CONNECTED_ON +#define LED_CONNECTED_ON do {} while(0) +#define LED_CONNECTED_OFF do {} while(0) +#endif +#ifndef LED_EP0_ON +#define LED_EP0_ON do {} while (0) +#define LED_EP0_OFF do {} while (0) +#endif + +static struct pxa27x_udc *the_controller; + +#if 0 +/*-------------------------------------------------------------------------*/ + + +/* one GPIO should be used to detect host disconnect */ +static inline int is_usb_connected(void) +{ + if (!the_controller->mach->udc_is_connected) + return 1; + return the_controller->mach->udc_is_connected(); +} + +/* one GPIO should force the host to see this device (or not) */ +static inline void make_usb_disappear(void) +{ + if (!the_controller->mach->udc_command) + return; + the_controller->mach->udc_command(PXA27X_UDC_CMD_DISCONNECT); +} + +static inline void let_usb_appear(void) +{ + if (!the_controller->mach->udc_command) + return; + the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); +} +#endif + +/*-------------------------------------------------------------------------*/ + +/* + * Debugging support vanishes in non-debug builds. DBG_NORMAL should be + * mostly silent during normal use/testing, with no timing side-effects. + */ +#define DBG_NORMAL 1 /* error paths, device state transitions */ +#define DBG_VERBOSE 2 /* add some success path trace info */ +#define DBG_NOISY 3 /* ... even more: request level */ +#define DBG_VERY_NOISY 4 /* ... even more: packet level */ + +#ifdef DEBUG + +static const char *state_name[] = { + "EP0_IDLE", + "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE", + "EP0_END_XFER", "EP0_STALL" +}; + +#define DMSG(stuff...) printk(KERN_ERR "udc: " stuff) + +#ifdef VERBOSE +# define UDC_DEBUG DBG_VERBOSE +#else +# define UDC_DEBUG DBG_NORMAL +#endif + +static void __attribute__ ((__unused__)) +dump_udccr(const char *label) +{ + u32 udccr = UDCCR; + DMSG("%s 0x%08x =%s%s%s%s%s%s%s%s%s%s, con=%d,inter=%d,altinter=%d\n", + label, udccr, + (udccr & UDCCR_OEN) ? " oen":"", + (udccr & UDCCR_AALTHNP) ? " aalthnp":"", + (udccr & UDCCR_AHNP) ? " rem" : "", + (udccr & UDCCR_BHNP) ? " rstir" : "", + (udccr & UDCCR_DWRE) ? " dwre" : "", + (udccr & UDCCR_SMAC) ? " smac" : "", + (udccr & UDCCR_EMCE) ? " emce" : "", + (udccr & UDCCR_UDR) ? " udr" : "", + (udccr & UDCCR_UDA) ? " uda" : "", + (udccr & UDCCR_UDE) ? " ude" : "", + (udccr & UDCCR_ACN) >> UDCCR_ACN_S, + (udccr & UDCCR_AIN) >> UDCCR_AIN_S, + (udccr & UDCCR_AAISN)>> UDCCR_AAISN_S ); +} + +static void __attribute__ ((__unused__)) +dump_udccsr0(const char *label) +{ + u32 udccsr0 = UDCCSR0; + + DMSG("%s %s 0x%08x =%s%s%s%s%s%s%s\n", + label, state_name[the_controller->ep0state], udccsr0, + (udccsr0 & UDCCSR0_SA) ? " sa" : "", + (udccsr0 & UDCCSR0_RNE) ? " rne" : "", + (udccsr0 & UDCCSR0_FST) ? " fst" : "", + (udccsr0 & UDCCSR0_SST) ? " sst" : "", + (udccsr0 & UDCCSR0_DME) ? " dme" : "", + (udccsr0 & UDCCSR0_IPR) ? " ipr" : "", + (udccsr0 & UDCCSR0_OPC) ? " opr" : ""); +} + +static void __attribute__ ((__unused__)) +dump_state(struct pxa27x_udc *dev) +{ + unsigned i; + + DMSG("%s, udcicr %02X.%02X, udcsir %02X.%02x, udcfnr %02X\n", + state_name[dev->ep0state], + UDCICR1, UDCICR0, UDCISR1, UDCISR0, UDCFNR); + dump_udccr("udccr"); + + if (!dev->driver) { + DMSG("no gadget driver bound\n"); + return; + } else + DMSG("ep0 driver '%s'\n", dev->driver->driver.name); + + + dump_udccsr0 ("udccsr0"); + DMSG("ep0 IN %lu/%lu, OUT %lu/%lu\n", + dev->stats.write.bytes, dev->stats.write.ops, + dev->stats.read.bytes, dev->stats.read.ops); + + for (i = 1; i < UDC_EP_NUM; i++) { + if (dev->ep [i].desc == 0) + continue; + DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccsr); + } +} + +#if 0 +static void dump_regs(u8 ep) +{ + DMSG("EP:%d UDCCSR:0x%08x UDCBCR:0x%08x\n UDCCR:0x%08x\n", + ep,UDCCSN(ep), UDCBCN(ep), UDCCN(ep)); +} +static void dump_req (struct pxa27x_request *req) +{ + struct usb_request *r = &req->req; + + DMSG("%s: buf:0x%08x length:%d dma:0x%08x actual:%d\n", + __FUNCTION__, (unsigned)r->buf, r->length, + r->dma, r->actual); +} +#endif + +#else + +#define DMSG(stuff...) do{}while(0) + +#define dump_udccr(x) do{}while(0) +#define dump_udccsr0(x) do{}while(0) +#define dump_state(x) do{}while(0) + +#define UDC_DEBUG ((unsigned)0) + +#endif + +#define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0) + +#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) +#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) + + +#endif /* __LINUX_USB_GADGET_PXA27X_H */ diff -urN linux-2.6.24.2/drivers/usb/gadget/pxa2xx_udc_gpio.c linux-2.6.24.2-vpac1/drivers/usb/gadget/pxa2xx_udc_gpio.c --- linux-2.6.24.2/drivers/usb/gadget/pxa2xx_udc_gpio.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/pxa2xx_udc_gpio.c 2008-02-22 13:52:46.000000000 +0100 @@ -0,0 +1,72 @@ +/* + * pxa2xx_udc_gpio.c: Generic driver for GPIO-controlled PXA2xx UDC. + * + * */ + +#include +#include +#include +#include +#include +#include + +static struct pxa2xx_udc_gpio_info *pdata; + +static void pda_udc_command(int cmd) +{ + switch (cmd) { + case PXA2XX_UDC_CMD_DISCONNECT: + DPM_DEBUG("pda_udc: Turning off port\n"); + dpm_power(&pdata->power_ctrl, 0); + break; + case PXA2XX_UDC_CMD_CONNECT: + DPM_DEBUG("pda_udc: Turning on port\n"); + dpm_power(&pdata->power_ctrl, 1); + break; + default: + printk("pda_udc: unknown command!\n"); + break; + } +} + +static int pda_udc_is_connected(void) +{ + int status = !!gpiodev_get_value(&pdata->detect_gpio) ^ pdata->detect_gpio_negative; + return status; +} + +static struct pxa2xx_udc_mach_info pda_udc_info __initdata = { + .udc_is_connected = pda_udc_is_connected, + .udc_command = pda_udc_command, +}; + +static int pda_udc_probe(struct platform_device * pdev) +{ + printk("pxa2xx-udc-gpio: Generic driver for GPIO-controlled PXA2xx UDC\n"); + pdata = pdev->dev.platform_data; + + pxa_set_udc_info(&pda_udc_info); + return 0; +} + +static struct platform_driver pda_udc_driver = { + .driver = { + .name = "pxa2xx-udc-gpio", + }, + .probe = pda_udc_probe, +}; + +static int __init pda_udc_init(void) +{ + return platform_driver_register(&pda_udc_driver); +} + +#ifdef MODULE +module_init(pda_udc_init); +#else /* start early for dependencies */ +fs_initcall(pda_udc_init); +#endif + +MODULE_AUTHOR("Paul Sokolovsky "); +MODULE_DESCRIPTION("Generic driver for GPIO-controlled PXA2xx UDC"); +MODULE_LICENSE("GPL"); diff -urN linux-2.6.24.2/drivers/usb/gadget/rndis.c linux-2.6.24.2-vpac1/drivers/usb/gadget/rndis.c --- linux-2.6.24.2/drivers/usb/gadget/rndis.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/rndis.c 2008-02-22 13:52:46.000000000 +0100 @@ -53,7 +53,7 @@ */ #if 0 -#define DBG(str,args...) do { \ +#define DEBUG(str,args...) do { \ if (rndis_debug) \ printk(KERN_DEBUG str , ## args ); \ } while (0) @@ -65,7 +65,7 @@ #else #define rndis_debug 0 -#define DBG(str,args...) do{}while(0) +#define DEBUG(str,args...) do{}while(0) #endif #define RNDIS_MAX_CONFIGS 1 @@ -183,17 +183,13 @@ if (!resp) return -ENOMEM; if (buf_len && rndis_debug > 1) { - DBG("query OID %08x value, len %d:\n", OID, buf_len); + DEBUG("query OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) { - DBG("%03d: %08x %08x %08x %08x\n", i, - le32_to_cpu(get_unaligned((__le32 *) - &buf[i])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 4])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 8])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 12]))); + DEBUG ("%03d: %08x %08x %08x %08x\n", i, + le32_to_cpup((__le32 *)&buf[i]), + le32_to_cpup((__le32 *)&buf[i + 4]), + le32_to_cpup((__le32 *)&buf[i + 8]), + le32_to_cpup((__le32 *)&buf[i + 12])); } } @@ -207,7 +203,7 @@ /* mandatory */ case OID_GEN_SUPPORTED_LIST: - DBG("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__); + DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__); length = sizeof (oid_supported_list); count = length / sizeof (u32); for (i = 0; i < count; i++) @@ -217,7 +213,7 @@ /* mandatory */ case OID_GEN_HARDWARE_STATUS: - DBG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__); + DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__); /* Bogus question! * Hardware must be ready to receive high level protocols. * BTW: @@ -230,14 +226,14 @@ /* mandatory */ case OID_GEN_MEDIA_SUPPORTED: - DBG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__); + DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__); *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); retval = 0; break; /* mandatory */ case OID_GEN_MEDIA_IN_USE: - DBG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__); + DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__); /* one medium, one transport... (maybe you do it better) */ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); retval = 0; @@ -245,7 +241,7 @@ /* mandatory */ case OID_GEN_MAXIMUM_FRAME_SIZE: - DBG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__); + DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); @@ -256,7 +252,7 @@ /* mandatory */ case OID_GEN_LINK_SPEED: if (rndis_debug > 1) - DBG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); + DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); if (rndis_per_dev_params [configNr].media_state == NDIS_MEDIA_STATE_DISCONNECTED) *outbuf = __constant_cpu_to_le32 (0); @@ -268,7 +264,7 @@ /* mandatory */ case OID_GEN_TRANSMIT_BLOCK_SIZE: - DBG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__); + DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); @@ -278,7 +274,7 @@ /* mandatory */ case OID_GEN_RECEIVE_BLOCK_SIZE: - DBG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__); + DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].dev->mtu); @@ -288,7 +284,7 @@ /* mandatory */ case OID_GEN_VENDOR_ID: - DBG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__); + DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__); *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].vendorID); retval = 0; @@ -296,7 +292,7 @@ /* mandatory */ case OID_GEN_VENDOR_DESCRIPTION: - DBG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__); + DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__); length = strlen (rndis_per_dev_params [configNr].vendorDescr); memcpy (outbuf, rndis_per_dev_params [configNr].vendorDescr, length); @@ -304,7 +300,7 @@ break; case OID_GEN_VENDOR_DRIVER_VERSION: - DBG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__); + DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__); /* Created as LE */ *outbuf = rndis_driver_version; retval = 0; @@ -312,14 +308,14 @@ /* mandatory */ case OID_GEN_CURRENT_PACKET_FILTER: - DBG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__); + DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__); *outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter); retval = 0; break; /* mandatory */ case OID_GEN_MAXIMUM_TOTAL_SIZE: - DBG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__); + DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE); retval = 0; break; @@ -327,14 +323,14 @@ /* mandatory */ case OID_GEN_MEDIA_CONNECT_STATUS: if (rndis_debug > 1) - DBG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__); + DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__); *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .media_state); retval = 0; break; case OID_GEN_PHYSICAL_MEDIUM: - DBG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__); + DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; @@ -344,7 +340,7 @@ * versions emit undefined RNDIS messages. DOCUMENT ALL THESE! */ case OID_GEN_MAC_OPTIONS: /* from WinME */ - DBG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__); + DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32( NDIS_MAC_OPTION_RECEIVE_SERIALIZED | NDIS_MAC_OPTION_FULL_DUPLEX); @@ -356,7 +352,7 @@ /* mandatory */ case OID_GEN_XMIT_OK: if (rndis_debug > 1) - DBG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); + DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].stats->tx_packets - @@ -369,7 +365,7 @@ /* mandatory */ case OID_GEN_RCV_OK: if (rndis_debug > 1) - DBG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); + DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 ( rndis_per_dev_params [configNr].stats->rx_packets - @@ -382,7 +378,7 @@ /* mandatory */ case OID_GEN_XMIT_ERROR: if (rndis_debug > 1) - DBG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__); + DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_errors); @@ -393,7 +389,7 @@ /* mandatory */ case OID_GEN_RCV_ERROR: if (rndis_debug > 1) - DBG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__); + DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_errors); @@ -403,7 +399,7 @@ /* mandatory */ case OID_GEN_RCV_NO_BUFFER: - DBG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__); + DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_dropped); @@ -413,7 +409,7 @@ #ifdef RNDIS_OPTIONAL_STATS case OID_GEN_DIRECTED_BYTES_XMIT: - DBG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__); + DEBUG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__); /* * Aunt Tilly's size of shoes * minus antarctica count of penguins @@ -433,7 +429,7 @@ break; case OID_GEN_DIRECTED_FRAMES_XMIT: - DBG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__); + DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__); /* dito */ if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 ( @@ -449,7 +445,7 @@ break; case OID_GEN_MULTICAST_BYTES_XMIT: - DBG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__); + DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast*1234); @@ -458,7 +454,7 @@ break; case OID_GEN_MULTICAST_FRAMES_XMIT: - DBG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__); + DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast); @@ -467,7 +463,7 @@ break; case OID_GEN_BROADCAST_BYTES_XMIT: - DBG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__); + DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_packets/42*255); @@ -476,7 +472,7 @@ break; case OID_GEN_BROADCAST_FRAMES_XMIT: - DBG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__); + DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->tx_packets/42); @@ -485,19 +481,19 @@ break; case OID_GEN_DIRECTED_BYTES_RCV: - DBG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__); + DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; case OID_GEN_DIRECTED_FRAMES_RCV: - DBG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__); + DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; case OID_GEN_MULTICAST_BYTES_RCV: - DBG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__); + DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast * 1111); @@ -506,7 +502,7 @@ break; case OID_GEN_MULTICAST_FRAMES_RCV: - DBG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__); + DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->multicast); @@ -515,7 +511,7 @@ break; case OID_GEN_BROADCAST_BYTES_RCV: - DBG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__); + DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_packets/42*255); @@ -524,7 +520,7 @@ break; case OID_GEN_BROADCAST_FRAMES_RCV: - DBG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__); + DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_packets/42); @@ -533,7 +529,7 @@ break; case OID_GEN_RCV_CRC_ERROR: - DBG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__); + DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_crc_errors); @@ -542,7 +538,7 @@ break; case OID_GEN_TRANSMIT_QUEUE_LENGTH: - DBG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__); + DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; @@ -552,7 +548,7 @@ /* mandatory */ case OID_802_3_PERMANENT_ADDRESS: - DBG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__); + DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { length = ETH_ALEN; memcpy (outbuf, @@ -564,7 +560,7 @@ /* mandatory */ case OID_802_3_CURRENT_ADDRESS: - DBG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__); + DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__); if (rndis_per_dev_params [configNr].dev) { length = ETH_ALEN; memcpy (outbuf, @@ -576,7 +572,7 @@ /* mandatory */ case OID_802_3_MULTICAST_LIST: - DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); + DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); /* Multicast base address only */ *outbuf = __constant_cpu_to_le32 (0xE0000000); retval = 0; @@ -584,21 +580,21 @@ /* mandatory */ case OID_802_3_MAXIMUM_LIST_SIZE: - DBG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); + DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); /* Multicast base address only */ *outbuf = __constant_cpu_to_le32 (1); retval = 0; break; case OID_802_3_MAC_OPTIONS: - DBG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__); + DEBUG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__); break; /* ieee802.3 statistics OIDs (table 4-4) */ /* mandatory */ case OID_802_3_RCV_ERROR_ALIGNMENT: - DBG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__); + DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__); if (rndis_per_dev_params [configNr].stats) { *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr] .stats->rx_frame_errors); @@ -608,51 +604,51 @@ /* mandatory */ case OID_802_3_XMIT_ONE_COLLISION: - DBG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__); + DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; /* mandatory */ case OID_802_3_XMIT_MORE_COLLISIONS: - DBG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__); + DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__); *outbuf = __constant_cpu_to_le32 (0); retval = 0; break; #ifdef RNDIS_OPTIONAL_STATS case OID_802_3_XMIT_DEFERRED: - DBG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__); + DEBUG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__); /* TODO */ break; case OID_802_3_XMIT_MAX_COLLISIONS: - DBG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__); + DEBUG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__); /* TODO */ break; case OID_802_3_RCV_OVERRUN: - DBG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__); + DEBUG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__); /* TODO */ break; case OID_802_3_XMIT_UNDERRUN: - DBG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__); + DEBUG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__); /* TODO */ break; case OID_802_3_XMIT_HEARTBEAT_FAILURE: - DBG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__); + DEBUG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__); /* TODO */ break; case OID_802_3_XMIT_TIMES_CRS_LOST: - DBG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__); + DEBUG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__); /* TODO */ break; case OID_802_3_XMIT_LATE_COLLISIONS: - DBG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__); + DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__); /* TODO */ break; #endif /* RNDIS_OPTIONAL_STATS */ @@ -660,7 +656,7 @@ #ifdef RNDIS_PM /* power management OIDs (table 4-5) */ case OID_PNP_CAPABILITIES: - DBG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__); + DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__); /* for now, no wakeup capabilities */ length = sizeof (struct NDIS_PNP_CAPABILITIES); @@ -668,8 +664,8 @@ retval = 0; break; case OID_PNP_QUERY_POWER: - DBG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__, - le32_to_cpu(get_unaligned((__le32 *)buf)) - 1); + DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__, + le32_to_cpup((__le32 *) buf) - 1); /* only suspend is a real power state, and * it can't be entered by OID_PNP_SET_POWER... */ @@ -705,17 +701,13 @@ return -ENOMEM; if (buf_len && rndis_debug > 1) { - DBG("set OID %08x value, len %d:\n", OID, buf_len); + DEBUG("set OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) { - DBG("%03d: %08x %08x %08x %08x\n", i, - le32_to_cpu(get_unaligned((__le32 *) - &buf[i])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 4])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 8])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 12]))); + DEBUG ("%03d: %08x %08x %08x %08x\n", i, + le32_to_cpup((__le32 *)&buf[i]), + le32_to_cpup((__le32 *)&buf[i + 4]), + le32_to_cpup((__le32 *)&buf[i + 8]), + le32_to_cpup((__le32 *)&buf[i + 12])); } } @@ -729,9 +721,8 @@ * PROMISCUOUS, DIRECTED, * MULTICAST, ALL_MULTICAST, BROADCAST */ - *params->filter = (u16) le32_to_cpu(get_unaligned( - (__le32 *)buf)); - DBG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", + *params->filter = (u16) le32_to_cpup((__le32 *)buf); + DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", __FUNCTION__, *params->filter); /* this call has a significant side effect: it's @@ -756,7 +747,7 @@ case OID_802_3_MULTICAST_LIST: /* I think we can ignore this */ - DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); + DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); retval = 0; break; #if 0 @@ -764,7 +755,7 @@ { struct rndis_config_parameter *param; param = (struct rndis_config_parameter *) buf; - DBG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n", + DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n", __FUNCTION__, min(cpu_to_le32(param->ParameterNameLength),80), buf + param->ParameterNameOffset); @@ -780,8 +771,8 @@ * resuming, Windows forces a reset, and then SET_POWER D0. * FIXME ... then things go batty; Windows wedges itself. */ - i = le32_to_cpu(get_unaligned((__le32 *)buf)); - DBG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1); + i = le32_to_cpup((__force __le32 *)buf); + DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1); switch (i) { case NdisDeviceStateD0: *params->filter = params->saved_filter; @@ -858,7 +849,7 @@ rndis_query_cmplt_type *resp; rndis_resp_t *r; - // DBG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID)); + // DEBUG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID)); if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP; /* @@ -911,15 +902,15 @@ BufOffset = le32_to_cpu (buf->InformationBufferOffset); #ifdef VERBOSE - DBG("%s: Length: %d\n", __FUNCTION__, BufLength); - DBG("%s: Offset: %d\n", __FUNCTION__, BufOffset); - DBG("%s: InfoBuffer: ", __FUNCTION__); + DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength); + DEBUG("%s: Offset: %d\n", __FUNCTION__, BufOffset); + DEBUG("%s: InfoBuffer: ", __FUNCTION__); for (i = 0; i < BufLength; i++) { - DBG("%02x ", *(((u8 *) buf) + i + 8 + BufOffset)); + DEBUG ("%02x ", *(((u8 *) buf) + i + 8 + BufOffset)); } - DBG("\n"); + DEBUG ("\n"); #endif resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT); @@ -1067,8 +1058,8 @@ return -ENOMEM; tmp = (__le32 *) buf; - MsgType = le32_to_cpu(get_unaligned(tmp++)); - MsgLength = le32_to_cpu(get_unaligned(tmp++)); + MsgType = le32_to_cpup(tmp++); + MsgLength = le32_to_cpup(tmp++); if (configNr >= RNDIS_MAX_CONFIGS) return -ENOTSUPP; @@ -1082,14 +1073,14 @@ /* For USB: responses may take up to 10 seconds */ switch (MsgType) { case REMOTE_NDIS_INITIALIZE_MSG: - DBG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", + DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", __FUNCTION__ ); params->state = RNDIS_INITIALIZED; return rndis_init_response (configNr, (rndis_init_msg_type *) buf); case REMOTE_NDIS_HALT_MSG: - DBG("%s: REMOTE_NDIS_HALT_MSG\n", + DEBUG("%s: REMOTE_NDIS_HALT_MSG\n", __FUNCTION__ ); params->state = RNDIS_UNINITIALIZED; if (params->dev) { @@ -1107,7 +1098,7 @@ (rndis_set_msg_type *) buf); case REMOTE_NDIS_RESET_MSG: - DBG("%s: REMOTE_NDIS_RESET_MSG\n", + DEBUG("%s: REMOTE_NDIS_RESET_MSG\n", __FUNCTION__ ); return rndis_reset_response (configNr, (rndis_reset_msg_type *) buf); @@ -1115,7 +1106,7 @@ case REMOTE_NDIS_KEEPALIVE_MSG: /* For USB: host does this every 5 seconds */ if (rndis_debug > 1) - DBG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", + DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", __FUNCTION__ ); return rndis_keepalive_response (configNr, (rndis_keepalive_msg_type *) @@ -1132,7 +1123,7 @@ { unsigned i; for (i = 0; i < MsgLength; i += 16) { - DBG("%03d: " + DEBUG ("%03d: " " %02x %02x %02x %02x" " %02x %02x %02x %02x" " %02x %02x %02x %02x" @@ -1163,18 +1154,18 @@ if (!rndis_per_dev_params [i].used) { rndis_per_dev_params [i].used = 1; rndis_per_dev_params [i].ack = rndis_control_ack; - DBG("%s: configNr = %d\n", __FUNCTION__, i); + DEBUG("%s: configNr = %d\n", __FUNCTION__, i); return i; } } - DBG("failed\n"); + DEBUG("failed\n"); return -1; } void rndis_deregister (int configNr) { - DBG("%s: \n", __FUNCTION__ ); + DEBUG("%s: \n", __FUNCTION__ ); if (configNr >= RNDIS_MAX_CONFIGS) return; rndis_per_dev_params [configNr].used = 0; @@ -1186,7 +1177,7 @@ struct net_device_stats *stats, u16 *cdc_filter) { - DBG("%s:\n", __FUNCTION__ ); + DEBUG("%s:\n", __FUNCTION__ ); if (!dev || !stats) return -1; if (configNr >= RNDIS_MAX_CONFIGS) return -1; @@ -1199,7 +1190,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr) { - DBG("%s:\n", __FUNCTION__ ); + DEBUG("%s:\n", __FUNCTION__ ); if (!vendorDescr) return -1; if (configNr >= RNDIS_MAX_CONFIGS) return -1; @@ -1211,7 +1202,7 @@ int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed) { - DBG("%s: %u %u\n", __FUNCTION__, medium, speed); + DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed); if (configNr >= RNDIS_MAX_CONFIGS) return -1; rndis_per_dev_params [configNr].medium = medium; @@ -1390,7 +1381,7 @@ break; default: if (fl_speed) p->speed = speed; - else DBG("%c is not valid\n", c); + else DEBUG ("%c is not valid\n", c); break; } @@ -1419,12 +1410,12 @@ if (!(rndis_connect_state [i] = create_proc_entry (name, 0660, NULL))) { - DBG("%s :remove entries", __FUNCTION__); + DEBUG ("%s :remove entries", __FUNCTION__); while (i) { sprintf (name, NAME_TEMPLATE, --i); remove_proc_entry (name, NULL); } - DBG("\n"); + DEBUG ("\n"); return -EIO; } diff -urN linux-2.6.24.2/drivers/usb/gadget/rndis.h linux-2.6.24.2-vpac1/drivers/usb/gadget/rndis.h --- linux-2.6.24.2/drivers/usb/gadget/rndis.h 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/rndis.h 2008-02-22 13:52:46.000000000 +0100 @@ -195,7 +195,7 @@ __le32 PerPacketInfoLength; __le32 VcHandle; __le32 Reserved; -} __attribute__ ((packed)); +}; struct rndis_config_parameter { diff -urN linux-2.6.24.2/drivers/usb/gadget/serial.c linux-2.6.24.2-vpac1/drivers/usb/gadget/serial.c --- linux-2.6.24.2/drivers/usb/gadget/serial.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/serial.c 2008-02-22 13:52:46.000000000 +0100 @@ -17,15 +17,34 @@ * */ +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include #include #include #include +#include +#include +#include +#include +#include +#include + #include #include -#include +#include #include "gadget_chips.h" @@ -70,29 +89,30 @@ #define GS_DEFAULT_PARITY USB_CDC_NO_PARITY #define GS_DEFAULT_CHAR_FORMAT USB_CDC_1_STOP_BITS -/* maxpacket and other transfer characteristics vary by speed. */ -static inline struct usb_endpoint_descriptor * -choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, - struct usb_endpoint_descriptor *fs) -{ - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return hs; - return fs; -} - +/* select highspeed/fullspeed, hiding highspeed if not configured */ +#ifdef CONFIG_USB_GADGET_DUALSPEED +#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs)) +#else +#define GS_SPEED_SELECT(is_hs,hs,fs) (fs) +#endif /* CONFIG_USB_GADGET_DUALSPEED */ /* debug settings */ -#ifdef DEBUG +#ifdef GS_DEBUG static int debug = 1; -#else -#define debug 0 -#endif #define gs_debug(format, arg...) \ do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0) #define gs_debug_level(level, format, arg...) \ do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0) +#else + +#define gs_debug(format, arg...) \ + do { } while(0) +#define gs_debug_level(level, format, arg...) \ + do { } while(0) + +#endif /* GS_DEBUG */ /* Thanks to NetChip Technologies for donating this product ID. * @@ -127,10 +147,10 @@ /* the port structure holds info for each port, one for each minor number */ struct gs_port { - struct gs_dev *port_dev; /* pointer to device struct */ + struct gs_dev *port_dev; /* pointer to device struct */ struct tty_struct *port_tty; /* pointer to tty struct */ spinlock_t port_lock; - int port_num; + int port_num; int port_open_count; int port_in_use; /* open/close in progress */ wait_queue_head_t port_write_wait;/* waiting to write */ @@ -168,7 +188,7 @@ /* tty driver */ static int gs_open(struct tty_struct *tty, struct file *file); static void gs_close(struct tty_struct *tty, struct file *file); -static int gs_write(struct tty_struct *tty, +static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count); static void gs_put_char(struct tty_struct *tty, unsigned char ch); static void gs_flush_chars(struct tty_struct *tty); @@ -202,7 +222,7 @@ static void gs_disconnect(struct usb_gadget *gadget); static int gs_set_config(struct gs_dev *dev, unsigned config); static void gs_reset_config(struct gs_dev *dev); -static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, +static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, @@ -239,7 +259,7 @@ static const char *EP_OUT_NAME; static const char *EP_NOTIFY_NAME; -static struct mutex gs_open_close_lock[GS_NUM_PORTS]; +static struct semaphore gs_open_close_sem[GS_NUM_PORTS]; static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE; static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE; @@ -395,18 +415,18 @@ }; static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = { - .bLength = sizeof(gs_call_mgmt_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, - .bmCapabilities = 0, - .bDataInterface = 1, /* index of data interface */ + .bLength = sizeof(gs_call_mgmt_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, + .bmCapabilities = 0, + .bDataInterface = 1, /* index of data interface */ }; static struct usb_cdc_acm_descriptor gs_acm_descriptor = { - .bLength = sizeof(gs_acm_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ACM_TYPE, - .bmCapabilities = 0, + .bLength = sizeof(gs_acm_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_ACM_TYPE, + .bmCapabilities = 0, }; static const struct usb_cdc_union_desc gs_union_desc = { @@ -416,7 +436,7 @@ .bMasterInterface0 = 0, /* index of control interface */ .bSlaveInterface0 = 1, /* index of data interface */ }; - + static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -462,6 +482,7 @@ NULL, }; +#ifdef CONFIG_USB_GADGET_DUALSPEED static struct usb_endpoint_descriptor gs_highspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -515,13 +536,15 @@ NULL, }; +#endif /* CONFIG_USB_GADGET_DUALSPEED */ + /* Module */ MODULE_DESCRIPTION(GS_LONG_NAME); MODULE_AUTHOR("Al Borchers"); MODULE_LICENSE("GPL"); -#ifdef DEBUG +#ifdef GS_DEBUG module_param(debug, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on"); #endif @@ -573,7 +596,7 @@ tty_set_operations(gs_tty_driver, &gs_tty_ops); for (i=0; i < GS_NUM_PORTS; i++) - mutex_init(&gs_open_close_lock[i]); + sema_init(&gs_open_close_sem[i], 1); retval = tty_register_driver(gs_tty_driver); if (retval) { @@ -613,7 +636,7 @@ struct gs_port *port; struct gs_dev *dev; struct gs_buf *buf; - struct mutex *mtx; + struct semaphore *sem; int ret; port_num = tty->index; @@ -634,10 +657,10 @@ return -ENODEV; } - mtx = &gs_open_close_lock[port_num]; - if (mutex_lock_interruptible(mtx)) { + sem = &gs_open_close_sem[port_num]; + if (down_interruptible(sem)) { printk(KERN_ERR - "gs_open: (%d,%p,%p) interrupted waiting for mutex\n", + "gs_open: (%d,%p,%p) interrupted waiting for semaphore\n", port_num, tty, file); return -ERESTARTSYS; } @@ -732,12 +755,12 @@ exit_unlock_port: spin_unlock_irqrestore(&port->port_lock, flags); - mutex_unlock(mtx); + up(sem); return ret; exit_unlock_dev: spin_unlock_irqrestore(&dev->dev_lock, flags); - mutex_unlock(mtx); + up(sem); return ret; } @@ -759,7 +782,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) { struct gs_port *port = tty->driver_data; - struct mutex *mtx; + struct semaphore *sem; if (port == NULL) { printk(KERN_ERR "gs_close: NULL port pointer\n"); @@ -768,8 +791,8 @@ gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file); - mtx = &gs_open_close_lock[port->port_num]; - mutex_lock(mtx); + sem = &gs_open_close_sem[port->port_num]; + down(sem); spin_lock_irq(&port->port_lock); @@ -824,7 +847,7 @@ exit: spin_unlock_irq(&port->port_lock); - mutex_unlock(mtx); + up(sem); } /* @@ -892,8 +915,7 @@ return; } - gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n", - port->port_num, tty, ch, __builtin_return_address(0)); + gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2)); spin_lock_irqsave(&port->port_lock, flags); @@ -1094,11 +1116,7 @@ len = gs_send_packet(dev, req->buf, ep->maxpacket); if (len > 0) { - gs_debug_level(3, "gs_send: len=%d, 0x%2.2x " - "0x%2.2x 0x%2.2x ...\n", len, - *((unsigned char *)req->buf), - *((unsigned char *)req->buf+1), - *((unsigned char *)req->buf+2)); +gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2)); list_del(&req_entry->re_entry); req->length = len; spin_unlock_irqrestore(&dev->dev_lock, flags); @@ -1251,7 +1269,7 @@ switch(req->status) { case 0: - /* normal completion */ + /* normal completion */ gs_recv_packet(dev, req->buf, req->actual); requeue: req->length = ep->maxpacket; @@ -1338,6 +1356,7 @@ struct usb_ep *ep; struct gs_dev *dev; int gcnum; + struct usb_endpoint_config ep_config[2]; /* Some controllers can't support CDC ACM: * - sh doesn't support multiple interfaces or configs; @@ -1358,22 +1377,33 @@ __constant_cpu_to_le16(GS_VERSION_NUM|0x0099); } + ep_config[0].config = GS_BULK_CONFIG_ID; + ep_config[0].interface = gs_bulk_interface_desc.bInterfaceNumber; + ep_config[0].altinterface = gs_bulk_interface_desc.bAlternateSetting; + ep_config[1].config = GS_ACM_CONFIG_ID; + ep_config[1].interface = gs_data_interface_desc.bInterfaceNumber; + ep_config[1].altinterface = gs_data_interface_desc.bAlternateSetting; + usb_ep_autoconfig_reset(gadget); - ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc); + ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc, &ep_config[0], 2); if (!ep) goto autoconf_fail; EP_IN_NAME = ep->name; ep->driver_data = ep; /* claim the endpoint */ - ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc); + ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc, &ep_config[0], 2); if (!ep) goto autoconf_fail; EP_OUT_NAME = ep->name; ep->driver_data = ep; /* claim the endpoint */ if (use_acm) { - ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc); + ep_config[0].config = GS_ACM_CONFIG_ID; + ep_config[0].interface = gs_control_interface_desc.bInterfaceNumber; + ep_config[0].altinterface = gs_control_interface_desc.bAlternateSetting; + + ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc, &ep_config[0], 1); if (!ep) { printk(KERN_ERR "gs_bind: cannot run ACM on %s\n", gadget->name); goto autoconf_fail; @@ -1388,30 +1418,29 @@ ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; - if (gadget_is_dualspeed(gadget)) { - gs_qualifier_desc.bDeviceClass = use_acm - ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; - /* assume ep0 uses the same packet size for both speeds */ - gs_qualifier_desc.bMaxPacketSize0 = - gs_device_desc.bMaxPacketSize0; - /* assume endpoints are dual-speed */ - gs_highspeed_notify_desc.bEndpointAddress = - gs_fullspeed_notify_desc.bEndpointAddress; - gs_highspeed_in_desc.bEndpointAddress = - gs_fullspeed_in_desc.bEndpointAddress; - gs_highspeed_out_desc.bEndpointAddress = - gs_fullspeed_out_desc.bEndpointAddress; - } +#ifdef CONFIG_USB_GADGET_DUALSPEED + gs_qualifier_desc.bDeviceClass = use_acm + ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; + /* assume ep0 uses the same packet size for both speeds */ + gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0; + /* assume endpoints are dual-speed */ + gs_highspeed_notify_desc.bEndpointAddress = + gs_fullspeed_notify_desc.bEndpointAddress; + gs_highspeed_in_desc.bEndpointAddress = + gs_fullspeed_in_desc.bEndpointAddress; + gs_highspeed_out_desc.bEndpointAddress = + gs_fullspeed_out_desc.bEndpointAddress; +#endif /* CONFIG_USB_GADGET_DUALSPEED */ usb_gadget_set_selfpowered(gadget); - if (gadget_is_otg(gadget)) { + if (gadget->is_otg) { gs_otg_descriptor.bmAttributes |= USB_OTG_HNP, gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - gs_device = dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL); + gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL); if (dev == NULL) return -ENOMEM; @@ -1419,6 +1448,7 @@ init_utsname()->sysname, init_utsname()->release, gadget->name); + memset(dev, 0, sizeof(struct gs_dev)); dev->dev_gadget = gadget; spin_lock_init(&dev->dev_lock); INIT_LIST_HEAD(&dev->dev_req_list); @@ -1470,12 +1500,6 @@ dev->dev_ctrl_req = NULL; } gs_free_ports(dev); - if (dev->dev_notify_ep) - usb_ep_disable(dev->dev_notify_ep); - if (dev->dev_in_ep) - usb_ep_disable(dev->dev_in_ep); - if (dev->dev_out_ep) - usb_ep_disable(dev->dev_out_ep); kfree(dev); set_gadget_data(gadget, NULL); } @@ -1559,8 +1583,9 @@ memcpy(req->buf, &gs_device_desc, ret); break; +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget_is_dualspeed(gadget)) + if (!gadget->is_dualspeed) break; ret = min(wLength, (u16)sizeof(struct usb_qualifier_descriptor)); @@ -1568,13 +1593,14 @@ break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget_is_dualspeed(gadget)) + if (!gadget->is_dualspeed) break; /* fall through */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - ret = gs_build_config_buf(req->buf, gadget, + ret = gs_build_config_buf(req->buf, gadget->speed, wValue >> 8, wValue & 0xff, - gadget_is_otg(gadget)); + gadget->is_otg); if (ret >= 0) ret = min(wLength, (u16)ret); break; @@ -1678,12 +1704,14 @@ switch (ctrl->bRequest) { case USB_CDC_REQ_SET_LINE_CODING: - /* FIXME Submit req to read the data; have its completion - * handler copy that data to port->port_line_coding (iff - * it's valid) and maybe pass it on. Until then, fail. - */ - printk(KERN_WARNING "gs_setup: set_line_coding " - "unuspported\n"); + ret = min(wLength, + (u16)sizeof(struct usb_cdc_line_coding)); + if (port) { + spin_lock(&port->port_lock); + memcpy(&port->port_line_coding, req->buf, ret); + spin_unlock(&port->port_lock); + } + ret = 0; break; case USB_CDC_REQ_GET_LINE_CODING: @@ -1698,18 +1726,11 @@ break; case USB_CDC_REQ_SET_CONTROL_LINE_STATE: - /* FIXME Submit req to read the data; have its completion - * handler use that to set the state (iff it's valid) and - * maybe pass it on. Until then, fail. - */ - printk(KERN_WARNING "gs_setup: set_control_line_state " - "unuspported\n"); + ret = 0; break; default: - printk(KERN_ERR "gs_setup: unknown class request, " - "type=%02x, request=%02x, value=%04x, " - "index=%04x, length=%d\n", + printk(KERN_ERR "gs_setup: unknown class request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); break; @@ -1814,7 +1835,8 @@ if (EP_NOTIFY_NAME && strcmp(ep->name, EP_NOTIFY_NAME) == 0) { - ep_desc = choose_ep_desc(gadget, + ep_desc = GS_SPEED_SELECT( + gadget->speed == USB_SPEED_HIGH, &gs_highspeed_notify_desc, &gs_fullspeed_notify_desc); ret = usb_ep_enable(ep,ep_desc); @@ -1830,8 +1852,9 @@ } else if (strcmp(ep->name, EP_IN_NAME) == 0) { - ep_desc = choose_ep_desc(gadget, - &gs_highspeed_in_desc, + ep_desc = GS_SPEED_SELECT( + gadget->speed == USB_SPEED_HIGH, + &gs_highspeed_in_desc, &gs_fullspeed_in_desc); ret = usb_ep_enable(ep,ep_desc); if (ret == 0) { @@ -1846,7 +1869,8 @@ } else if (strcmp(ep->name, EP_OUT_NAME) == 0) { - ep_desc = choose_ep_desc(gadget, + ep_desc = GS_SPEED_SELECT( + gadget->speed == USB_SPEED_HIGH, &gs_highspeed_out_desc, &gs_fullspeed_out_desc); ret = usb_ep_enable(ep,ep_desc); @@ -1965,11 +1989,11 @@ * Builds the config descriptors in the given buffer and returns the * length, or a negative error number. */ -static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, +static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, u8 type, unsigned int index, int is_otg) { int len; - int high_speed = 0; + int high_speed; const struct usb_config_descriptor *config_desc; const struct usb_descriptor_header **function; @@ -1977,22 +2001,20 @@ return -EINVAL; /* other speed switches high and full speed */ - if (gadget_is_dualspeed(g)) { - high_speed = (g->speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - high_speed = !high_speed; - } + high_speed = (speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + high_speed = !high_speed; if (use_acm) { config_desc = &gs_acm_config_desc; - function = high_speed - ? gs_acm_highspeed_function - : gs_acm_fullspeed_function; + function = GS_SPEED_SELECT(high_speed, + gs_acm_highspeed_function, + gs_acm_fullspeed_function); } else { config_desc = &gs_bulk_config_desc; - function = high_speed - ? gs_bulk_highspeed_function - : gs_bulk_fullspeed_function; + function = GS_SPEED_SELECT(high_speed, + gs_bulk_highspeed_function, + gs_bulk_fullspeed_function); } /* for now, don't advertise srp-only devices */ @@ -2206,7 +2228,7 @@ * * Free the buffer and all associated memory. */ -static void gs_buf_free(struct gs_buf *gb) +void gs_buf_free(struct gs_buf *gb) { if (gb) { kfree(gb->buf_buf); @@ -2219,7 +2241,7 @@ * * Clear out all data in the circular buffer. */ -static void gs_buf_clear(struct gs_buf *gb) +void gs_buf_clear(struct gs_buf *gb) { if (gb != NULL) gb->buf_get = gb->buf_put; @@ -2232,7 +2254,7 @@ * Return the number of bytes of data available in the circular * buffer. */ -static unsigned int gs_buf_data_avail(struct gs_buf *gb) +unsigned int gs_buf_data_avail(struct gs_buf *gb) { if (gb != NULL) return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size; @@ -2246,7 +2268,7 @@ * Return the number of bytes of space available in the circular * buffer. */ -static unsigned int gs_buf_space_avail(struct gs_buf *gb) +unsigned int gs_buf_space_avail(struct gs_buf *gb) { if (gb != NULL) return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size; @@ -2262,8 +2284,7 @@ * * Return the number of bytes copied. */ -static unsigned int -gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count) +unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count) { unsigned int len; @@ -2301,8 +2322,7 @@ * * Return the number of bytes copied. */ -static unsigned int -gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count) +unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count) { unsigned int len; diff -urN linux-2.6.24.2/drivers/usb/gadget/usbstring.c linux-2.6.24.2-vpac1/drivers/usb/gadget/usbstring.c --- linux-2.6.24.2/drivers/usb/gadget/usbstring.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/usbstring.c 2008-02-22 13:52:46.000000000 +0100 @@ -15,7 +15,7 @@ #include #include -#include +#include #include diff -urN linux-2.6.24.2/drivers/usb/gadget/zero.c linux-2.6.24.2-vpac1/drivers/usb/gadget/zero.c --- linux-2.6.24.2/drivers/usb/gadget/zero.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/usb/gadget/zero.c 2008-02-22 13:52:46.000000000 +0100 @@ -1,22 +1,38 @@ /* * zero.c -- Gadget Zero, for USB development * - * Copyright (C) 2003-2007 David Brownell + * Copyright (C) 2003-2004 David Brownell * All rights reserved. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -41,28 +57,41 @@ * Many drivers will only have one configuration, letting them be much * simpler if they also don't support high speed operation (like this * driver does). - * - * Why is *this* driver using two configurations, rather than setting up - * two interfaces with different functions? To help verify that multiple - * configuration infrastucture is working correctly; also, so that it can - * work with low capability USB controllers without four bulk endpoints. */ -/* #define VERBOSE_DEBUG */ +#define DEBUG 1 +// #define VERBOSE +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include + +#include +#include +#include +#include +#include #include -#include +#include #include "gadget_chips.h" /*-------------------------------------------------------------------------*/ -#define DRIVER_VERSION "Lughnasadh, 2007" +#define DRIVER_VERSION "St Patrick's Day 2004" static const char shortname [] = "zero"; static const char longname [] = "Gadget Zero"; @@ -103,16 +132,30 @@ struct timer_list resume; }; -#define DBG(d, fmt, args...) \ - dev_dbg(&(d)->gadget->dev , fmt , ## args) -#define VDBG(d, fmt, args...) \ - dev_vdbg(&(d)->gadget->dev , fmt , ## args) -#define ERROR(d, fmt, args...) \ - dev_err(&(d)->gadget->dev , fmt , ## args) -#define WARN(d, fmt, args...) \ - dev_warn(&(d)->gadget->dev , fmt , ## args) -#define INFO(d, fmt, args...) \ - dev_info(&(d)->gadget->dev , fmt , ## args) +#define xprintk(d,level,fmt,args...) \ + dev_printk(level , &(d)->gadget->dev , fmt , ## args) + +#ifdef DEBUG +#define DBG(dev,fmt,args...) \ + xprintk(dev , KERN_DEBUG , fmt , ## args) +#else +#define DBG(dev,fmt,args...) \ + do { } while (0) +#endif /* DEBUG */ + +#ifdef VERBOSE +#define VDBG DBG +#else +#define VDBG(dev,fmt,args...) \ + do { } while (0) +#endif /* VERBOSE */ + +#define ERROR(dev,fmt,args...) \ + xprintk(dev , KERN_ERR , fmt , ## args) +#define WARN(dev,fmt,args...) \ + xprintk(dev , KERN_WARNING , fmt , ## args) +#define INFO(dev,fmt,args...) \ + xprintk(dev , KERN_INFO , fmt , ## args) /*-------------------------------------------------------------------------*/ @@ -284,6 +327,8 @@ NULL, }; +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -339,20 +384,17 @@ }; /* maxpacket and other transfer characteristics vary by speed. */ -static inline struct usb_endpoint_descriptor * -ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, - struct usb_endpoint_descriptor *fs) -{ - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return hs; - return fs; -} +#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) + +#else -static char manufacturer[50]; +/* if there's no high speed support, maxpacket doesn't change. */ +#define ep_desc(g,hs,fs) fs -/* default serial number takes at least two packets */ -static char serial[] = "0123456789.0123456789.0123456789"; +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +static char manufacturer [50]; +static char serial [40]; /* static strings, in UTF-8 */ static struct usb_string strings [] = { @@ -394,29 +436,30 @@ int is_source_sink; int len; const struct usb_descriptor_header **function; - int hs = 0; +#ifdef CONFIG_USB_GADGET_DUALSPEED + int hs = (gadget->speed == USB_SPEED_HIGH); +#endif /* two configurations will always be index 0 and index 1 */ if (index > 1) return -EINVAL; is_source_sink = loopdefault ? (index == 1) : (index == 0); - if (gadget_is_dualspeed(gadget)) { - hs = (gadget->speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; - } +#ifdef CONFIG_USB_GADGET_DUALSPEED + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; if (hs) function = is_source_sink ? hs_source_sink_function : hs_loopback_function; else +#endif function = is_source_sink ? fs_source_sink_function : fs_loopback_function; /* for now, don't advertise srp-only devices */ - if (!gadget_is_otg(gadget)) + if (!gadget->is_otg) function++; len = usb_gadget_config_buf (is_source_sink @@ -439,7 +482,8 @@ req = usb_ep_alloc_request (ep, GFP_ATOMIC); if (req) { req->length = length; - req->buf = kmalloc(length, GFP_ATOMIC); + req->buf = usb_ep_alloc_buffer (ep, length, + &req->dma, GFP_ATOMIC); if (!req->buf) { usb_ep_free_request (ep, req); req = NULL; @@ -450,25 +494,13 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req) { - kfree(req->buf); + if (req->buf) + usb_ep_free_buffer (ep, req->buf, req->dma, req->length); usb_ep_free_request (ep, req); } /*-------------------------------------------------------------------------*/ -/* - * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals, - * this just sinks bulk packets OUT to the peripheral and sources them IN - * to the host, optionally with specific data patterns. - * - * In terms of control messaging, this supports all the standard requests - * plus two that support control-OUT tests. - * - * Note that because this doesn't queue more than one request at a time, - * some other function must be used to test queueing logic. The network - * link (g_ether) is probably the best option for that. - */ - /* optionally require specific source/sink data patterns */ static int @@ -505,7 +537,12 @@ return 0; } -static void reinit_write_data(struct usb_ep *ep, struct usb_request *req) +static void +reinit_write_data ( + struct zero_dev *dev, + struct usb_ep *ep, + struct usb_request *req +) { unsigned i; u8 *buf = req->buf; @@ -532,16 +569,16 @@ switch (status) { - case 0: /* normal completion? */ + case 0: /* normal completion? */ if (ep == dev->out_ep) { check_read_data (dev, ep, req); memset (req->buf, 0x55, req->length); } else - reinit_write_data(ep, req); + reinit_write_data (dev, ep, req); break; /* this endpoint is normally active while we're configured */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status, @@ -573,7 +610,8 @@ } } -static struct usb_request *source_sink_start_ep(struct usb_ep *ep) +static struct usb_request * +source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) { struct usb_request *req; int status; @@ -586,11 +624,11 @@ req->complete = source_sink_complete; if (strcmp (ep->name, EP_IN_NAME) == 0) - reinit_write_data(ep, req); + reinit_write_data (ep->driver_data, ep, req); else memset (req->buf, 0x55, req->length); - status = usb_ep_queue(ep, req, GFP_ATOMIC); + status = usb_ep_queue (ep, req, gfp_flags); if (status) { struct zero_dev *dev = ep->driver_data; @@ -602,7 +640,8 @@ return req; } -static int set_source_sink_config(struct zero_dev *dev) +static int +set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_ep *ep; @@ -617,7 +656,7 @@ result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; - if (source_sink_start_ep(ep) != NULL) { + if (source_sink_start_ep (ep, gfp_flags) != 0) { dev->in_ep = ep; continue; } @@ -631,7 +670,7 @@ result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; - if (source_sink_start_ep(ep) != NULL) { + if (source_sink_start_ep (ep, gfp_flags) != 0) { dev->out_ep = ep; continue; } @@ -663,7 +702,7 @@ switch (status) { - case 0: /* normal completion? */ + case 0: /* normal completion? */ if (ep == dev->out_ep) { /* loop this OUT packet back IN to the host */ req->zero = (req->actual < req->length); @@ -697,7 +736,7 @@ * rely on the hardware driver to clean up on disconnect or * endpoint disable. */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ free_ep_req (ep, req); @@ -705,7 +744,8 @@ } } -static int set_loopback_config(struct zero_dev *dev) +static int +set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_ep *ep; @@ -805,7 +845,8 @@ * code can do, perhaps by disallowing more than one configuration or * by limiting configuration choices (like the pxa2xx). */ -static int zero_set_config(struct zero_dev *dev, unsigned number) +static int +zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -815,17 +856,17 @@ if (gadget_is_sa1100 (gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ - ERROR(dev, "can't change configurations\n"); + INFO (dev, "can't change configurations\n"); return -ESPIPE; } zero_reset_config (dev); switch (number) { case CONFIG_SOURCE_SINK: - result = set_source_sink_config(dev); + result = set_source_sink_config (dev, gfp_flags); break; case CONFIG_LOOPBACK: - result = set_loopback_config(dev); + result = set_loopback_config (dev, gfp_flags); break; default: result = -EINVAL; @@ -845,7 +886,7 @@ case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; + default: speed = "?"; break; } dev->config = number; @@ -898,17 +939,19 @@ value = min (w_length, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget_is_dualspeed(gadget)) + if (!gadget->is_dualspeed) break; value = min (w_length, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget_is_dualspeed(gadget)) + if (!gadget->is_dualspeed) break; // FALLTHROUGH +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: value = config_buf (gadget, req->buf, w_value >> 8, @@ -942,7 +985,7 @@ else VDBG (dev, "HNP inactive\n"); spin_lock (&dev->lock); - value = zero_set_config(dev, w_value); + value = zero_set_config (dev, w_value, GFP_ATOMIC); spin_unlock (&dev->lock); break; case USB_REQ_GET_CONFIGURATION: @@ -971,7 +1014,7 @@ * use this "reset the config" shortcut. */ zero_reset_config (dev); - zero_set_config(dev, config); + zero_set_config (dev, config, GFP_ATOMIC); value = 0; } spin_unlock (&dev->lock); @@ -1100,6 +1143,7 @@ struct zero_dev *dev; struct usb_ep *ep; int gcnum; + struct usb_endpoint_config ep_config[2]; /* FIXME this can't yet work right with SH ... it has only * one configuration, numbered one. @@ -1112,7 +1156,15 @@ * but there may also be important quirks to address. */ usb_ep_autoconfig_reset (gadget); - ep = usb_ep_autoconfig (gadget, &fs_source_desc); + + ep_config[0].config = CONFIG_SOURCE_SINK; + ep_config[0].interface = source_sink_intf.bInterfaceNumber; + ep_config[0].altinterface = source_sink_intf.bAlternateSetting; + ep_config[1].config = CONFIG_LOOPBACK; + ep_config[1].interface = loopback_intf.bInterfaceNumber; + ep_config[1].altinterface = loopback_intf.bAlternateSetting; + + ep = usb_ep_autoconfig(gadget, &fs_source_desc, &ep_config[0], 2); if (!ep) { autoconf_fail: printk (KERN_ERR "%s: can't autoconfigure on %s\n", @@ -1121,8 +1173,8 @@ } EP_IN_NAME = ep->name; ep->driver_data = ep; /* claim */ - - ep = usb_ep_autoconfig (gadget, &fs_sink_desc); + + ep = usb_ep_autoconfig(gadget, &fs_sink_desc, &ep_config[0], 2); if (!ep) goto autoconf_fail; EP_OUT_NAME = ep->name; @@ -1157,7 +1209,8 @@ dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); if (!dev->req) goto enomem; - dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); + dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ, + &dev->req->dma, GFP_KERNEL); if (!dev->req->buf) goto enomem; @@ -1165,18 +1218,16 @@ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; - if (gadget_is_dualspeed(gadget)) { - /* assume ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = - fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = - fs_sink_desc.bEndpointAddress; - } +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* assume ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; +#endif - if (gadget_is_otg(gadget)) { + if (gadget->is_otg) { otg_descriptor.bmAttributes |= USB_OTG_HNP, source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -1254,18 +1305,23 @@ .suspend = zero_suspend, .resume = zero_resume, - .driver = { + .driver = { .name = (char *) shortname, .owner = THIS_MODULE, }, }; -MODULE_AUTHOR("David Brownell"); -MODULE_LICENSE("GPL"); +MODULE_AUTHOR ("David Brownell"); +MODULE_LICENSE ("Dual BSD/GPL"); static int __init init (void) { + /* a real value would likely come through some id prom + * or module option. this one takes at least two packets. + */ + strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial); + return usb_gadget_register_driver (&zero_driver); } module_init (init); diff -urN linux-2.6.24.2/drivers/video/Kconfig linux-2.6.24.2-vpac1/drivers/video/Kconfig --- linux-2.6.24.2/drivers/video/Kconfig 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/video/Kconfig 2008-02-22 13:52:46.000000000 +0100 @@ -1729,6 +1729,51 @@ If unsure, say N. +choice + + depends on FB_PXA + prompt "PXA framebuffer device" + default FB_PXA_ANALOG + +config FB_PXA_ANALOG + bool "Analog DAC output" + +config FB_PXA_TX14D14VM1BBA + bool "HITACHI TX14D14VM1BBA" + +endchoice + +choice + + depends on FB_PXA && FB_PXA_ANALOG + prompt "PXA framebuffer resolution" + default FB_PXA_SVGA + +config FB_PXA_VGA + bool "VGA 640x480" + +config FB_PXA_SVGA + bool "SVGA 800x600" + +config FB_PXA_XGA + bool "XGA 1024x768" + +endchoice + +choice + + depends on FB_PXA && FB_PXA_ANALOG + prompt "PXA framebuffer bits per pixel" + default FB_PXA_BPP16 + +config FB_PXA_BPP8 + bool "8 bpp" + +config FB_PXA_BPP16 + bool "16 bpp" + +endchoice + config FB_PXA_PARAMETERS bool "PXA LCD command line parameters" default n diff -urN linux-2.6.24.2/drivers/video/pxafb.c linux-2.6.24.2-vpac1/drivers/video/pxafb.c --- linux-2.6.24.2/drivers/video/pxafb.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/drivers/video/pxafb.c 2008-02-22 23:28:44.000000000 +0100 @@ -1381,7 +1381,7 @@ goto failed; #endif -#ifdef DEBUG_VAR +#if DEBUG_VAR /* Check for various illegal bit-combinations. Currently only * a warning is given. */ diff -urN linux-2.6.24.2/include/asm-arm/arch-pxa/hardware.h linux-2.6.24.2-vpac1/include/asm-arm/arch-pxa/hardware.h --- linux-2.6.24.2/include/asm-arm/arch-pxa/hardware.h 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/include/asm-arm/arch-pxa/hardware.h 2008-02-22 13:52:46.000000000 +0100 @@ -44,7 +44,20 @@ #ifndef __ASSEMBLY__ +#if 0 # define __REG(x) (*((volatile u32 *)io_p2v(x))) +#else +/* + * This __REG() version gives the same results as the one above, except + * that we are fooling gcc somehow so it generates far better and smaller + * assembly code for access to contigous registers. It's a shame that gcc + * doesn't guess this by itself. + */ +#include +typedef struct { volatile u32 offset[4096]; } __regbase; +# define __REGP(x) ((__regbase *)((x)&~4095))->offset[((x)&4095)>>2] +# define __REG(x) __REGP(io_p2v(x)) +#endif /* With indexed regs we don't want to feed the index through io_p2v() especially if it is a variable, otherwise horrible code will result. */ @@ -213,4 +226,8 @@ #define pcibios_assign_all_busses() 1 #endif +#ifdef CONFIG_MACH_VPAC270 +#include "vpac270.h" +#endif + #endif /* _ASM_ARCH_HARDWARE_H */ diff -urN linux-2.6.24.2/include/asm-arm/arch-pxa/pxa-regs.h linux-2.6.24.2-vpac1/include/asm-arm/arch-pxa/pxa-regs.h --- linux-2.6.24.2/include/asm-arm/arch-pxa/pxa-regs.h 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/include/asm-arm/arch-pxa/pxa-regs.h 2008-02-22 13:52:46.000000000 +0100 @@ -108,6 +108,14 @@ #define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt (read / write) */ #define DALGN __REG(0x400000a0) /* DMA Alignment Register */ + +#define DRQSR0 __REG(0x400000e0) /* DMA Request Status Register 0 */ +#define DRQSR1 __REG(0x400000e4) /* DMA Request Status Register 1 */ +#define DRQSR2 __REG(0x400000e8) /* DMA Request Status Register 2 */ + +#define DRQSR_REQCLR (1 << 8) /* Clear Pending Requests */ +#define DRQSR_REQPEND 0x0000001f + #define DINT __REG(0x400000f0) /* DMA Interrupt Register */ #define DRCMR(n) (*(((n) < 64) ? \ @@ -276,6 +284,10 @@ #define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */ #define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ +/* default combinations */ +#define DCMD_RXPCDR (DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4) +#define DCMD_RXMCDR (DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4) +#define DCMD_TXPCDR (DCMD_INCSRCADDR|DCMD_FLOWTRG|DCMD_BURST32|DCMD_WIDTH4) /* * UARTs @@ -1319,6 +1331,7 @@ #define GPIO77_LCD_ACBIAS 77 /* LCD AC Bias */ #define GPIO78_nCS_2 78 /* chip select 2 */ #define GPIO79_nCS_3 79 /* chip select 3 */ +#define GPIO79_pSKTSEL 79 /* pSKTSEL - PC Card Socket select (PXA27xx)*/ #define GPIO80_nCS_4 80 /* chip select 4 */ #define GPIO81_NSCLK 81 /* NSSP clock */ #define GPIO82_NSFRM 82 /* NSSP Frame */ @@ -1358,6 +1371,7 @@ #define GPIO8_MMCCS0_MD ( 8 | GPIO_ALT_FN_1_OUT) #define GPIO9_MMCCS1_MD ( 9 | GPIO_ALT_FN_1_OUT) #define GPIO10_RTCCLK_MD (10 | GPIO_ALT_FN_1_OUT) +#define GPIO10_FFDCD_MD (10 | GPIO_ALT_FN_1_IN) #define GPIO11_3_6MHz_MD (11 | GPIO_ALT_FN_1_OUT) #define GPIO12_32KHz_MD (12 | GPIO_ALT_FN_1_OUT) #define GPIO13_MBGNT_MD (13 | GPIO_ALT_FN_2_OUT) @@ -1373,6 +1387,7 @@ #define GPIO25_STXD_MD (25 | GPIO_ALT_FN_2_OUT) #define GPIO26_SRXD_MD (26 | GPIO_ALT_FN_1_IN) #define GPIO27_SEXTCLK_MD (27 | GPIO_ALT_FN_1_IN) +#define GPIO27_FFRTS_MD (27 | GPIO_ALT_FN_3_OUT) #define GPIO28_BITCLK_AC97_MD (28 | GPIO_ALT_FN_1_IN) #define GPIO28_BITCLK_IN_I2S_MD (28 | GPIO_ALT_FN_2_IN) #define GPIO28_BITCLK_OUT_I2S_MD (28 | GPIO_ALT_FN_1_OUT) @@ -1386,6 +1401,7 @@ #define GPIO32_SYSCLK_I2S_MD (32 | GPIO_ALT_FN_1_OUT) #define GPIO32_MMCCLK_MD ( 32 | GPIO_ALT_FN_2_OUT) #define GPIO33_nCS_5_MD (33 | GPIO_ALT_FN_2_OUT) +#define GPIO33_FFDSR_MD (33 | GPIO_ALT_FN_2_IN) #define GPIO34_FFRXD_MD (34 | GPIO_ALT_FN_1_IN) #define GPIO34_MMCCS0_MD (34 | GPIO_ALT_FN_2_OUT) #define GPIO35_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) @@ -1469,6 +1485,7 @@ #define GPIO84_NSSP_RX (84 | GPIO_ALT_FN_2_IN) #define GPIO85_nPCE_1_MD (85 | GPIO_ALT_FN_1_OUT) #define GPIO92_MMCDAT0_MD (92 | GPIO_ALT_FN_1_OUT) +#define GPIO100_FFCTS_MD (100 | GPIO_ALT_FN_2_IN) #define GPIO102_nPCE_1_MD (102 | GPIO_ALT_FN_1_OUT) #define GPIO104_pSKTSEL_MD (104 | GPIO_ALT_FN_1_OUT) #define GPIO109_MMCDAT1_MD (109 | GPIO_ALT_FN_1_OUT) @@ -1840,6 +1857,7 @@ #define LCCR3_4BPP (2 << 24) #define LCCR3_8BPP (3 << 24) #define LCCR3_16BPP (4 << 24) +#define LCCR3_18BPP (5 << 24) #define LCCR3_PDFOR_0 (0 << 30) #define LCCR3_PDFOR_1 (1 << 30) diff -urN linux-2.6.24.2/include/asm-arm/arch-pxa/vpac270.h linux-2.6.24.2-vpac1/include/asm-arm/arch-pxa/vpac270.h --- linux-2.6.24.2/include/asm-arm/arch-pxa/vpac270.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/include/asm-arm/arch-pxa/vpac270.h 2008-02-22 13:52:46.000000000 +0100 @@ -0,0 +1,253 @@ +/* + * linux/include/asm-arm/arch-pxa/vpac270.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Copyright (c) 2006 Voipac Technologies + * + */ + +#include +#include + + +/* + * Note: include file for assembler and C + */ + +/* + * Video settings + */ + +#define VPAC270_ANALOG_VGA +//#define VPAC270_LCD_PHILIPSLB + +#ifdef VPAC270_ANALOG_VGA +/* set to 1 if you want these settings to be active */ +#define VPAC270_LCD_SETTINGS 1 + +/* set to GPIO that switches on the backlight */ +#define VPAC270_LCD_BLO_GPIO 81 + +/* set to 1 if the LCD is an active panel (TFT) or for VGA */ +#define VPAC270_LCD_ACTIVE 1 + +/* set to 1 if the LCD panel is a dual-scan panel */ +#define VPAC270_LCD_DUAL 0 + +/* set to 1 if the LCD BIAS pin should be active low (OEP) */ +#define VPAC270_BIAS_ACTIVE_LOW 0 + +/* set to 1 if the data is sampled on the falling edge of the pixel clock PCP*/ +#define VPAC270_PIX_CLK_FALLING 0 + +/* set to 3 if more than 16 bpp (PDFOR) */ +#define VPAC270_PIXEL_DATA_FORMAT 3 + +/* the following settings can also be set using fbset */ +/* these are settings are for analog VGA */ +#define LCD_PIXCLOCK 40000 +#define LCD_XRES 640 +#define LCD_YRES 480 +#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 64 +#define LCD_VERTICAL_SYNC_PULSE_WIDTH 2 +#define LCD_BEGIN_OF_LINE_WAIT_COUNT 96 +#define LCD_BEGIN_FRAME_WAIT_COUNT 33 +#define LCD_END_OF_LINE_WAIT_COUNT 48 +#define LCD_END_OF_FRAME_WAIT_COUNT 10 +#define LCD_SYNC 0 + + +/* VGA timings: +pixclk 0x1801050 Hz (25MHz) = 40000ps +640x480 18BPP +LCD_HORIZONTAL_SYNC_PULSE_WIDTH HSPW 0x40 +LCD_BEGIN_OF_LINE_WAIT_COUNT BLW 0x60 +LCD_END_OF_LINE_WAIT_COUNT ELW 0x30 +LCD_VERTICAL_SYNC_PULSE_WIDTH VSW 0x2 +LCD_BEGIN_FRAME_WAIT_COUNT BFW 0x21 +LCD_END_OF_FRAME_WAIT_COUNT EFW 0xa +VPAC270_PIX_CLK_FALLING PCP 0 +FB_SYNC_HOR_HIGH_ACT_LOW HSP 1 +FB_SYNC_VERT_HIGH_ACT_LOW VSP 1 +VPAC270_LCD_DUAL SDS 0 +VPAC270_LCD_ACTIVE PAS 1 +VPAC270_BIAS_ACTIVE_LOW OEP 0 +*/ + +#elif defined VPAC270_LCD_PHILIPSLB + +/* set to 1 if you want these settings to be active */ +#define VPAC270_LCD_SETTINGS 1 + +/* set to GPIO that switches on the backlight */ +#define VPAC270_LCD_BLO_GPIO 81 + +/* set to 1 if the LCD is an active panel (TFT) or for VGA */ +#define VPAC270_LCD_ACTIVE 1 + +/* set to 1 if the LCD panel is a dual-scan panel */ +#define VPAC270_LCD_DUAL 0 + +/* set to 1 if the LCD BIAS pin should be active low (OEP) */ +#define VPAC270_BIAS_ACTIVE_LOW 0 + +/* set to 1 if the data is sampled on the falling edge of the pixel clock PCP*/ +#define VPAC270_PIX_CLK_FALLING 1 + +/* set to 3 if more than 16 bpp (PDFOR) */ +#define VPAC270_PIXEL_DATA_FORMAT 3 + +/* the following settings can also be set using fbset */ +/* these are settings are for analog VGA */ +#define LCD_PIXCLOCK 40000 +#define LCD_XRES 640 +#define LCD_YRES 480 +#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 2 +#define LCD_VERTICAL_SYNC_PULSE_WIDTH 45 +#define LCD_BEGIN_OF_LINE_WAIT_COUNT 160 +#define LCD_BEGIN_FRAME_WAIT_COUNT 0 +#define LCD_END_OF_LINE_WAIT_COUNT 2 +#define LCD_END_OF_FRAME_WAIT_COUNT 0 +#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT) + +/* Philips LB064V02-A1 timings: +pixclk 0x1801050 Hz (25MHz) = 40000ps +640x480 18BPP +LCD_HORIZONTAL_SYNC_PULSE_WIDTH HSPW 2 +LCD_BEGIN_OF_LINE_WAIT_COUNT BLW 160 +LCD_END_OF_LINE_WAIT_COUNT ELW 2 +LCD_VERTICAL_SYNC_PULSE_WIDTH VSW 45 +LCD_BEGIN_FRAME_WAIT_COUNT BFW 0 +LCD_END_OF_FRAME_WAIT_COUNT EFW 0 +VPAC270_PIX_CLK_FALLING PCP 1 +FB_SYNC_HOR_HIGH_ACT_LOW HSP 0 +FB_SYNC_VERT_HIGH_ACT_LOW VSP 0 +VPAC270_LCD_DUAL SDS 0 +VPAC270_LCD_ACTIVE PAS 1 +VPAC270_BIAS_ACTIVE_LOW OEP 0 +*/ +#endif + + +/* + * physical memory map + */ + +#define VPAC270_FLASH_PHYS PXA_CS0_PHYS /* 0x00000000 */ +#define VPAC270_FLASH_SIZE (0x02000000) + +#define VPAC270_ETH_PHYS PXA_CS2_PHYS /* 0x08000000 */ +//#define VPAC270_CPLD_PHYS PXA_CS3_PHYS /* 0x0c000000 */ +#define VPAC270_BCR_PHYS 0x0e000000 + +/* + * virtual memory map + */ + +#define VPAC270_FLASH 0x00000000 +//#define VPAC270_ETH_BASE 0xf4000000 +#define VPAC270_ETH_SIZE 8 + +//#define VPAC270_CPLD_BASE 0xf0000000 +//#define VPAC270_CPLD_SIZE 0x04000000 +#define VPAC270_CF_OFFSET 0x00000000 +#define VPAC270_BCR_OFFSET 0x02000000 +#define VPAC270_IRDA_OFFSET 0x02400000 +#define VPAC270_UPS_OFFSET 0x02800000 +#define VPAC270_DCR_OFFSET 0x03800000 + +//#ifndef __ASSEMBLY__ +//# define CPLD_REG(x) (*((volatile unsigned short *)(VPAC270_CPLD_BASE + (x)))) +//#else +//# define CPLD_REG(x) (VPAC270_CPLD_BASE + (x)) +//#endif + + +//#define DM9000_BASE VPAC270_ETH_BASE +//#define DM9000_MMIO 1 +//#define DM9000_ADDRFROMTAG 1 + +#define VPAC270_CF0_STATUS CPLD_REG(VPAC270_CF_OFFSET) +#define VPAC270_BCR_CONTROL CPLD_REG(VPAC270_BCR_OFFSET) +#define VPAC270_DCR CPLD_REG(VPAC270_DCR_OFFSET) + +/* + * interrupts + */ +/* Ethernet */ +#define GPIO_ETH_IRQ 114 +#define VPAC270_ETH_IRQ IRQ_GPIO(GPIO_ETH_IRQ) +#define DM9000_IRQ VPAC270_ETH_IRQ + +/* IDE */ +#define GPIO_IDE_IRQ 36 +#define VPAC270_IDE_IRQ IRQ_GPIO(GPIO_IDE_IRQ) + +/* Compact Flash/PCMCIA */ +#define GPIO_PCMCIA0_CD_IRQ 84 +#define VPAC270_PCMCIA0_CD_IRQ IRQ_GPIO(GPIO_PCMCIA0_CD_IRQ) +#define GPIO_PCMCIA1_CD_IRQ 17 +#define VPAC270_PCMCIA1_CD_IRQ IRQ_GPIO(GPIO_PCMCIA1_CD_IRQ) +#define VPAC270_PCMCIA_CD_EDGE IRQT_BOTHEDGE +#define GPIO_PCMCIA0_RDY_IRQ 35 +#define VPAC270_PCMCIA0_RDY_IRQ IRQ_GPIO(GPIO_PCMCIA0_RDY_IRQ) +#define GPIO_PCMCIA1_RDY_IRQ 12 +#define VPAC270_PCMCIA1_RDY_IRQ IRQ_GPIO(GPIO_PCMCIA1_RDY_IRQ) +#define VPAC270_PCMCIA_RDY_EDGE IRQT_FALLING +#define GPIO_PCMCIA_POW_EN 107 +#define GPIO_PCMCIA_NPOE 48 +#define GPIO_PCMCIA_NPOE_AF GPIO_ALT_FN_2_OUT +#define GPIO_PCMCIA_NPIOR 50 +#define GPIO_PCMCIA_NPIOR_AF GPIO_ALT_FN_2_OUT +#define GPIO_PCMCIA_NPIOW 51 +#define GPIO_PCMCIA_NPIOW_AF GPIO_ALT_FN_2_OUT +#define GPIO_PCMCIA_NPCE1 85 +#define GPIO_PCMCIA_NPCE1_AF GPIO_ALT_FN_1_OUT +#define GPIO_PCMCIA_NPCE2 54 +#define GPIO_PCMCIA_NPCE2_AF GPIO_ALT_FN_2_OUT +#define GPIO_PCMCIA_NPREG 55 +#define GPIO_PCMCIA_NPREG_AF GPIO_ALT_FN_2_OUT +#define GPIO_PCMCIA_NPWAIT 56 +#define GPIO_PCMCIA_NPWAIT_AF GPIO_ALT_FN_1_IN +#define GPIO_PCMCIA_NPIOIS16 57 +#define GPIO_PCMCIA_NPIOIS16_AF GPIO_ALT_FN_1_IN +#define GPIO_PCMCIA_PSKTSEL 104 +#define GPIO_PCMCIA_PSKTSEL_AF GPIO_ALT_FN_1_OUT +#define GPIO_PCMCIA0_RESET 11 +#define GPIO_PCMCIA1_RESET 16 +//#define GPIO_PCMCIA0_BVD1 83 +//#define GPIO_PCMCIA0_BVD2 82 + +#define PCC0_DETECT (GPLR(GPIO_PCMCIA0_CD_IRQ) & GPIO_bit(GPIO_PCMCIA0_CD_IRQ)) +#define PCC0_READY (GPLR(GPIO_PCMCIA0_RDY_IRQ) & GPIO_bit(GPIO_PCMCIA0_RDY_IRQ)) +#define PCC1_DETECT (GPLR(GPIO_PCMCIA1_CD_IRQ) & GPIO_bit(GPIO_PCMCIA1_CD_IRQ)) +#define PCC1_READY (GPLR(GPIO_PCMCIA1_RDY_IRQ) & GPIO_bit(GPIO_PCMCIA1_RDY_IRQ)) +#define PCC_BVD1() (GPLR(GPIO_PCMCIA0_BVD1) & GPIO_bit(GPIO_PCMCIA0_BVD1)) +#define PCC_BVD2() (GPLR(GPIO_PCMCIA0_BVD2) & GPIO_bit(GPIO_PCMCIA0_BVD2)) +#define PCC_VS3V() 1 /* only 3.3V supported */ +#define PCC_VS5V() 0 /* only 3.3V supported */ +#define PCC_PWR_ON() (GPCR(GPIO_PCMCIA_POW_EN) |= GPIO_bit(GPIO_PCMCIA_POW_EN)) +#define PCC_PWR_OFF() (GPSR(GPIO_PCMCIA_POW_EN) |= GPIO_bit(GPIO_PCMCIA_POW_EN)) + +/* MMC/SD */ +#define GPIO_MMC_CD_IRQ 53 +#define VPAC270_MMC_CD_IRQ IRQ_GPIO(GPIO_MMC_CD_IRQ) +#define GPIO_MMCCLK_AF GPIO32_MMCCLK_MD +#define GPIO_MMCDAT0_AF GPIO92_MMCDAT0 +#define GPIO_MMCDAT1_AF GPIO109_MMCDAT1 +#define GPIO_MMCDAT2_AF GPIO110_MMCDAT2 +#define GPIO_MMCDAT3_AF GPIO111_MMCDAT3 +#define GPIO_MMCCMD_AF GPIO112_MMCCMD_MD +#define GPIO_MMCCS0_AF GPIO110_MMCCS0_MD + +/* TouchScreen and Sound */ +#define GPIO_TOUCH_IRQ 113 +#define VPAC270_TOUCH_IRQ IRQ_GPIO(GPIO_TOUCH_IRQ) + +#define GPIO_AC97_RESET 95 +#define GPIO_AC97_RST_AF GPIO_ALT_FN_1_OUT +#define GPIO_AC97_SYSCLK 98 +#define GPIO_AC97_SYSCLK_AF GPIO_ALT_FN_1_OUT diff -urN linux-2.6.24.2/include/linux/usb_gadget.h linux-2.6.24.2-vpac1/include/linux/usb_gadget.h --- linux-2.6.24.2/include/linux/usb_gadget.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.2-vpac1/include/linux/usb_gadget.h 2008-02-22 13:52:46.000000000 +0100 @@ -0,0 +1,902 @@ +/* + * + * + * We call the USB code inside a Linux-based peripheral device a "gadget" + * driver, except for the hardware-specific bus glue. One USB host can + * master many USB gadgets, but the gadgets are only slaved to one host. + * + * + * (C) Copyright 2002-2004 by David Brownell + * All Rights Reserved. + * + * This software is licensed under the GNU GPL version 2. + */ + +#ifndef __LINUX_USB_GADGET_H +#define __LINUX_USB_GADGET_H + +#ifdef __KERNEL__ + +struct usb_ep; + +/** + * struct usb_request - describes one i/o request + * @buf: Buffer used for data. Always provide this; some controllers + * only use PIO, or don't use DMA for some endpoints. + * @dma: DMA address corresponding to 'buf'. If you don't set this + * field, and the usb controller needs one, it is responsible + * for mapping and unmapping the buffer. + * @length: Length of that data + * @no_interrupt: If true, hints that no completion irq is needed. + * Helpful sometimes with deep request queues that are handled + * directly by DMA controllers. + * @zero: If true, when writing data, makes the last packet be "short" + * by adding a zero length packet as needed; + * @short_not_ok: When reading data, makes short packets be + * treated as errors (queue stops advancing till cleanup). + * @complete: Function called when request completes, so this request and + * its buffer may be re-used. + * Reads terminate with a short packet, or when the buffer fills, + * whichever comes first. When writes terminate, some data bytes + * will usually still be in flight (often in a hardware fifo). + * Errors (for reads or writes) stop the queue from advancing + * until the completion function returns, so that any transfers + * invalidated by the error may first be dequeued. + * @context: For use by the completion callback + * @list: For use by the gadget driver. + * @status: Reports completion code, zero or a negative errno. + * Normally, faults block the transfer queue from advancing until + * the completion callback returns. + * Code "-ESHUTDOWN" indicates completion caused by device disconnect, + * or when the driver disabled the endpoint. + * @actual: Reports bytes transferred to/from the buffer. For reads (OUT + * transfers) this may be less than the requested length. If the + * short_not_ok flag is set, short reads are treated as errors + * even when status otherwise indicates successful completion. + * Note that for writes (IN transfers) some data bytes may still + * reside in a device-side FIFO when the request is reported as + * complete. + * + * These are allocated/freed through the endpoint they're used with. The + * hardware's driver can add extra per-request data to the memory it returns, + * which often avoids separate memory allocations (potential failures), + * later when the request is queued. + * + * Request flags affect request handling, such as whether a zero length + * packet is written (the "zero" flag), whether a short read should be + * treated as an error (blocking request queue advance, the "short_not_ok" + * flag), or hinting that an interrupt is not required (the "no_interrupt" + * flag, for use with deep request queues). + * + * Bulk endpoints can use any size buffers, and can also be used for interrupt + * transfers. interrupt-only endpoints can be much less functional. + */ + // NOTE this is analagous to 'struct urb' on the host side, + // except that it's thinner and promotes more pre-allocation. + +struct usb_request { + void *buf; + unsigned length; + dma_addr_t dma; + + unsigned no_interrupt:1; + unsigned zero:1; + unsigned short_not_ok:1; + + void (*complete)(struct usb_ep *ep, + struct usb_request *req); + void *context; + struct list_head list; + + int status; + unsigned actual; +}; + +/*-------------------------------------------------------------------------*/ + +/* endpoint-specific parts of the api to the usb controller hardware. + * unlike the urb model, (de)multiplexing layers are not required. + * (so this api could slash overhead if used on the host side...) + * + * note that device side usb controllers commonly differ in how many + * endpoints they support, as well as their capabilities. + */ +struct usb_ep_ops { + int (*enable) (struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc); + int (*disable) (struct usb_ep *ep); + + struct usb_request *(*alloc_request) (struct usb_ep *ep, + gfp_t gfp_flags); + void (*free_request) (struct usb_ep *ep, struct usb_request *req); + + void *(*alloc_buffer) (struct usb_ep *ep, unsigned bytes, + dma_addr_t *dma, gfp_t gfp_flags); + void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma, + unsigned bytes); + // NOTE: on 2.6, drivers may also use dma_map() and + // dma_sync_single_*() to directly manage dma overhead. + + int (*queue) (struct usb_ep *ep, struct usb_request *req, + gfp_t gfp_flags); + int (*dequeue) (struct usb_ep *ep, struct usb_request *req); + + int (*set_halt) (struct usb_ep *ep, int value); + int (*fifo_status) (struct usb_ep *ep); + void (*fifo_flush) (struct usb_ep *ep); +}; + +/** + * struct usb_ep - device side representation of USB endpoint + * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk" + * @ops: Function pointers used to access hardware-specific operations. + * @ep_list:the gadget's ep_list holds all of its endpoints + * @maxpacket:The maximum packet size used on this endpoint. The initial + * value can sometimes be reduced (hardware allowing), according to + * the endpoint descriptor used to configure the endpoint. + * @driver_data:for use by the gadget driver. all other fields are + * read-only to gadget drivers. + * + * the bus controller driver lists all the general purpose endpoints in + * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list, + * and is accessed only in response to a driver setup() callback. + */ +struct usb_ep { + void *driver_data; + + const char *name; + const struct usb_ep_ops *ops; + struct list_head ep_list; + unsigned maxpacket:16; +}; + +/*-------------------------------------------------------------------------*/ + +/** + * usb_ep_enable - configure endpoint, making it usable + * @ep:the endpoint being configured. may not be the endpoint named "ep0". + * drivers discover endpoints through the ep_list of a usb_gadget. + * @desc:descriptor for desired behavior. caller guarantees this pointer + * remains valid until the endpoint is disabled; the data byte order + * is little-endian (usb-standard). + * + * when configurations are set, or when interface settings change, the driver + * will enable or disable the relevant endpoints. while it is enabled, an + * endpoint may be used for i/o until the driver receives a disconnect() from + * the host or until the endpoint is disabled. + * + * the ep0 implementation (which calls this routine) must ensure that the + * hardware capabilities of each endpoint match the descriptor provided + * for it. for example, an endpoint named "ep2in-bulk" would be usable + * for interrupt transfers as well as bulk, but it likely couldn't be used + * for iso transfers or for endpoint 14. some endpoints are fully + * configurable, with more generic names like "ep-a". (remember that for + * USB, "in" means "towards the USB master".) + * + * returns zero, or a negative error code. + */ +static inline int +usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) +{ + return ep->ops->enable (ep, desc); +} + +/** + * usb_ep_disable - endpoint is no longer usable + * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". + * + * no other task may be using this endpoint when this is called. + * any pending and uncompleted requests will complete with status + * indicating disconnect (-ESHUTDOWN) before this call returns. + * gadget drivers must call usb_ep_enable() again before queueing + * requests to the endpoint. + * + * returns zero, or a negative error code. + */ +static inline int +usb_ep_disable (struct usb_ep *ep) +{ + return ep->ops->disable (ep); +} + +/** + * usb_ep_alloc_request - allocate a request object to use with this endpoint + * @ep:the endpoint to be used with with the request + * @gfp_flags:GFP_* flags to use + * + * Request objects must be allocated with this call, since they normally + * need controller-specific setup and may even need endpoint-specific + * resources such as allocation of DMA descriptors. + * Requests may be submitted with usb_ep_queue(), and receive a single + * completion callback. Free requests with usb_ep_free_request(), when + * they are no longer needed. + * + * Returns the request, or null if one could not be allocated. + */ +static inline struct usb_request * +usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags) +{ + return ep->ops->alloc_request (ep, gfp_flags); +} + +/** + * usb_ep_free_request - frees a request object + * @ep:the endpoint associated with the request + * @req:the request being freed + * + * Reverses the effect of usb_ep_alloc_request(). + * Caller guarantees the request is not queued, and that it will + * no longer be requeued (or otherwise used). + */ +static inline void +usb_ep_free_request (struct usb_ep *ep, struct usb_request *req) +{ + ep->ops->free_request (ep, req); +} + +/** + * usb_ep_alloc_buffer - allocate an I/O buffer + * @ep:the endpoint associated with the buffer + * @len:length of the desired buffer + * @dma:pointer to the buffer's DMA address; must be valid + * @gfp_flags:GFP_* flags to use + * + * Returns a new buffer, or null if one could not be allocated. + * The buffer is suitably aligned for dma, if that endpoint uses DMA, + * and the caller won't have to care about dma-inconsistency + * or any hidden "bounce buffer" mechanism. No additional per-request + * DMA mapping will be required for such buffers. + * Free it later with usb_ep_free_buffer(). + * + * You don't need to use this call to allocate I/O buffers unless you + * want to make sure drivers don't incur costs for such "bounce buffer" + * copies or per-request DMA mappings. + */ +static inline void * +usb_ep_alloc_buffer (struct usb_ep *ep, unsigned len, dma_addr_t *dma, + gfp_t gfp_flags) +{ + return ep->ops->alloc_buffer (ep, len, dma, gfp_flags); +} + +/** + * usb_ep_free_buffer - frees an i/o buffer + * @ep:the endpoint associated with the buffer + * @buf:CPU view address of the buffer + * @dma:the buffer's DMA address + * @len:length of the buffer + * + * reverses the effect of usb_ep_alloc_buffer(). + * caller guarantees the buffer will no longer be accessed + */ +static inline void +usb_ep_free_buffer (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned len) +{ + ep->ops->free_buffer (ep, buf, dma, len); +} + +/** + * usb_ep_queue - queues (submits) an I/O request to an endpoint. + * @ep:the endpoint associated with the request + * @req:the request being submitted + * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't + * pre-allocate all necessary memory with the request. + * + * This tells the device controller to perform the specified request through + * that endpoint (reading or writing a buffer). When the request completes, + * including being canceled by usb_ep_dequeue(), the request's completion + * routine is called to return the request to the driver. Any endpoint + * (except control endpoints like ep0) may have more than one transfer + * request queued; they complete in FIFO order. Once a gadget driver + * submits a request, that request may not be examined or modified until it + * is given back to that driver through the completion callback. + * + * Each request is turned into one or more packets. The controller driver + * never merges adjacent requests into the same packet. OUT transfers + * will sometimes use data that's already buffered in the hardware. + * Drivers can rely on the fact that the first byte of the request's buffer + * always corresponds to the first byte of some USB packet, for both + * IN and OUT transfers. + * + * Bulk endpoints can queue any amount of data; the transfer is packetized + * automatically. The last packet will be short if the request doesn't fill it + * out completely. Zero length packets (ZLPs) should be avoided in portable + * protocols since not all usb hardware can successfully handle zero length + * packets. (ZLPs may be explicitly written, and may be implicitly written if + * the request 'zero' flag is set.) Bulk endpoints may also be used + * for interrupt transfers; but the reverse is not true, and some endpoints + * won't support every interrupt transfer. (Such as 768 byte packets.) + * + * Interrupt-only endpoints are less functional than bulk endpoints, for + * example by not supporting queueing or not handling buffers that are + * larger than the endpoint's maxpacket size. They may also treat data + * toggle differently. + * + * Control endpoints ... after getting a setup() callback, the driver queues + * one response (even if it would be zero length). That enables the + * status ack, after transfering data as specified in the response. Setup + * functions may return negative error codes to generate protocol stalls. + * (Note that some USB device controllers disallow protocol stall responses + * in some cases.) When control responses are deferred (the response is + * written after the setup callback returns), then usb_ep_set_halt() may be + * used on ep0 to trigger protocol stalls. + * + * For periodic endpoints, like interrupt or isochronous ones, the usb host + * arranges to poll once per interval, and the gadget driver usually will + * have queued some data to transfer at that time. + * + * Returns zero, or a negative error code. Endpoints that are not enabled + * report errors; errors will also be + * reported when the usb peripheral is disconnected. + */ +static inline int +usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) +{ + return ep->ops->queue (ep, req, gfp_flags); +} + +/** + * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint + * @ep:the endpoint associated with the request + * @req:the request being canceled + * + * if the request is still active on the endpoint, it is dequeued and its + * completion routine is called (with status -ECONNRESET); else a negative + * error code is returned. + * + * note that some hardware can't clear out write fifos (to unlink the request + * at the head of the queue) except as part of disconnecting from usb. such + * restrictions prevent drivers from supporting configuration changes, + * even to configuration zero (a "chapter 9" requirement). + */ +static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req) +{ + return ep->ops->dequeue (ep, req); +} + +/** + * usb_ep_set_halt - sets the endpoint halt feature. + * @ep: the non-isochronous endpoint being stalled + * + * Use this to stall an endpoint, perhaps as an error report. + * Except for control endpoints, + * the endpoint stays halted (will not stream any data) until the host + * clears this feature; drivers may need to empty the endpoint's request + * queue first, to make sure no inappropriate transfers happen. + * + * Note that while an endpoint CLEAR_FEATURE will be invisible to the + * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the + * current altsetting, see usb_ep_clear_halt(). When switching altsettings, + * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. + * + * Returns zero, or a negative error code. On success, this call sets + * underlying hardware state that blocks data transfers. + * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any + * transfer requests are still queued, or if the controller hardware + * (usually a FIFO) still holds bytes that the host hasn't collected. + */ +static inline int +usb_ep_set_halt (struct usb_ep *ep) +{ + return ep->ops->set_halt (ep, 1); +} + +/** + * usb_ep_clear_halt - clears endpoint halt, and resets toggle + * @ep:the bulk or interrupt endpoint being reset + * + * Use this when responding to the standard usb "set interface" request, + * for endpoints that aren't reconfigured, after clearing any other state + * in the endpoint's i/o queue. + * + * Returns zero, or a negative error code. On success, this call clears + * the underlying hardware state reflecting endpoint halt and data toggle. + * Note that some hardware can't support this request (like pxa2xx_udc), + * and accordingly can't correctly implement interface altsettings. + */ +static inline int +usb_ep_clear_halt (struct usb_ep *ep) +{ + return ep->ops->set_halt (ep, 0); +} + +/** + * usb_ep_fifo_status - returns number of bytes in fifo, or error + * @ep: the endpoint whose fifo status is being checked. + * + * FIFO endpoints may have "unclaimed data" in them in certain cases, + * such as after aborted transfers. Hosts may not have collected all + * the IN data written by the gadget driver (and reported by a request + * completion). The gadget driver may not have collected all the data + * written OUT to it by the host. Drivers that need precise handling for + * fault reporting or recovery may need to use this call. + * + * This returns the number of such bytes in the fifo, or a negative + * errno if the endpoint doesn't use a FIFO or doesn't support such + * precise handling. + */ +static inline int +usb_ep_fifo_status (struct usb_ep *ep) +{ + if (ep->ops->fifo_status) + return ep->ops->fifo_status (ep); + else + return -EOPNOTSUPP; +} + +/** + * usb_ep_fifo_flush - flushes contents of a fifo + * @ep: the endpoint whose fifo is being flushed. + * + * This call may be used to flush the "unclaimed data" that may exist in + * an endpoint fifo after abnormal transaction terminations. The call + * must never be used except when endpoint is not being used for any + * protocol translation. + */ +static inline void +usb_ep_fifo_flush (struct usb_ep *ep) +{ + if (ep->ops->fifo_flush) + ep->ops->fifo_flush (ep); +} + + +/*-------------------------------------------------------------------------*/ + +struct usb_gadget; + +/** + * struct usb_endpoint_config - possible configurations of a given endpoint + * @config: the configuration number + * @interface: the interface number + * @altinterface: the altinterface number + * + * Used as an array to pass information about the possible configurations + * of a given endpoint to the bus controller. + */ +struct usb_endpoint_config { + u8 config; + u8 interface; + u8 altinterface; +}; + +/* the rest of the api to the controller hardware: device operations, + * which don't involve endpoints (or i/o). + */ +struct usb_gadget_ops { + struct usb_ep* (*ep_alloc)(struct usb_gadget *, + struct usb_endpoint_descriptor *, + struct usb_endpoint_config *, int); + int (*get_frame)(struct usb_gadget *); + int (*wakeup)(struct usb_gadget *); + int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); + int (*vbus_session) (struct usb_gadget *, int is_active); + int (*vbus_draw) (struct usb_gadget *, unsigned mA); + int (*pullup) (struct usb_gadget *, int is_on); + int (*ioctl)(struct usb_gadget *, + unsigned code, unsigned long param); +}; + +/** + * struct usb_gadget - represents a usb slave device + * @ops: Function pointers used to access hardware-specific operations. + * @ep0: Endpoint zero, used when reading or writing responses to + * driver setup() requests + * @ep_list: List of other endpoints supported by the device. + * @speed: Speed of current connection to USB host. + * @is_dualspeed: True if the controller supports both high and full speed + * operation. If it does, the gadget driver must also support both. + * @is_otg: True if the USB device port uses a Mini-AB jack, so that the + * gadget driver must provide a USB OTG descriptor. + * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable + * is in the Mini-AB jack, and HNP has been used to switch roles + * so that the "A" device currently acts as A-Peripheral, not A-Host. + * @a_hnp_support: OTG device feature flag, indicating that the A-Host + * supports HNP at this port. + * @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host + * only supports HNP on a different root port. + * @b_hnp_enable: OTG device feature flag, indicating that the A-Host + * enabled HNP support. + * @name: Identifies the controller hardware type. Used in diagnostics + * and sometimes configuration. + * @dev: Driver model state for this abstract device. + * + * Gadgets have a mostly-portable "gadget driver" implementing device + * functions, handling all usb configurations and interfaces. Gadget + * drivers talk to hardware-specific code indirectly, through ops vectors. + * That insulates the gadget driver from hardware details, and packages + * the hardware endpoints through generic i/o queues. The "usb_gadget" + * and "usb_ep" interfaces provide that insulation from the hardware. + * + * Except for the driver data, all fields in this structure are + * read-only to the gadget driver. That driver data is part of the + * "driver model" infrastructure in 2.6 (and later) kernels, and for + * earlier systems is grouped in a similar structure that's not known + * to the rest of the kernel. + * + * Values of the three OTG device feature flags are updated before the + * setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before + * driver suspend() calls. They are valid only when is_otg, and when the + * device is acting as a B-Peripheral (so is_a_peripheral is false). + */ +struct usb_gadget { + /* readonly to gadget driver */ + const struct usb_gadget_ops *ops; + struct usb_ep *ep0; + struct list_head ep_list; /* of usb_ep */ + enum usb_device_speed speed; + unsigned is_dualspeed:1; + unsigned is_otg:1; + unsigned is_a_peripheral:1; + unsigned b_hnp_enable:1; + unsigned a_hnp_support:1; + unsigned a_alt_hnp_support:1; + const char *name; + struct device dev; +}; + +static inline void set_gadget_data (struct usb_gadget *gadget, void *data) + { dev_set_drvdata (&gadget->dev, data); } +static inline void *get_gadget_data (struct usb_gadget *gadget) + { return dev_get_drvdata (&gadget->dev); } + +/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */ +#define gadget_for_each_ep(tmp,gadget) \ + list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) + + +/** + * usb_gadget_frame_number - returns the current frame number + * @gadget: controller that reports the frame number + * + * Returns the usb frame number, normally eleven bits from a SOF packet, + * or negative errno if this device doesn't support this capability. + */ +static inline int usb_gadget_frame_number (struct usb_gadget *gadget) +{ + return gadget->ops->get_frame (gadget); +} + +/** + * usb_gadget_wakeup - tries to wake up the host connected to this gadget + * @gadget: controller used to wake up the host + * + * Returns zero on success, else negative error code if the hardware + * doesn't support such attempts, or its support has not been enabled + * by the usb host. Drivers must return device descriptors that report + * their ability to support this, or hosts won't enable it. + * + * This may also try to use SRP to wake the host and start enumeration, + * even if OTG isn't otherwise in use. OTG devices may also start + * remote wakeup even when hosts don't explicitly enable it. + */ +static inline int usb_gadget_wakeup (struct usb_gadget *gadget) +{ + if (!gadget->ops->wakeup) + return -EOPNOTSUPP; + return gadget->ops->wakeup (gadget); +} + +/** + * usb_gadget_set_selfpowered - sets the device selfpowered feature. + * @gadget:the device being declared as self-powered + * + * this affects the device status reported by the hardware driver + * to reflect that it now has a local power supply. + * + * returns zero on success, else negative errno. + */ +static inline int +usb_gadget_set_selfpowered (struct usb_gadget *gadget) +{ + if (!gadget->ops->set_selfpowered) + return -EOPNOTSUPP; + return gadget->ops->set_selfpowered (gadget, 1); +} + +/** + * usb_gadget_clear_selfpowered - clear the device selfpowered feature. + * @gadget:the device being declared as bus-powered + * + * this affects the device status reported by the hardware driver. + * some hardware may not support bus-powered operation, in which + * case this feature's value can never change. + * + * returns zero on success, else negative errno. + */ +static inline int +usb_gadget_clear_selfpowered (struct usb_gadget *gadget) +{ + if (!gadget->ops->set_selfpowered) + return -EOPNOTSUPP; + return gadget->ops->set_selfpowered (gadget, 0); +} + +/** + * usb_gadget_vbus_connect - Notify controller that VBUS is powered + * @gadget:The device which now has VBUS power. + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session starting. Common responses include + * resuming the controller, activating the D+ (or D-) pullup to let the + * host detect that a USB device is attached, and starting to draw power + * (8mA or possibly more, especially after SET_CONFIGURATION). + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_connect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session (gadget, 1); +} + +/** + * usb_gadget_vbus_draw - constrain controller's VBUS power usage + * @gadget:The device whose VBUS usage is being described + * @mA:How much current to draw, in milliAmperes. This should be twice + * the value listed in the configuration descriptor bMaxPower field. + * + * This call is used by gadget drivers during SET_CONFIGURATION calls, + * reporting how much power the device may consume. For example, this + * could affect how quickly batteries are recharged. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + if (!gadget->ops->vbus_draw) + return -EOPNOTSUPP; + return gadget->ops->vbus_draw (gadget, mA); +} + +/** + * usb_gadget_vbus_disconnect - notify controller about VBUS session end + * @gadget:the device whose VBUS supply is being described + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session ending. Common responses include + * reversing everything done in usb_gadget_vbus_connect(). + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_disconnect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session (gadget, 0); +} + +/** + * usb_gadget_connect - software-controlled connect to USB host + * @gadget:the peripheral being connected + * + * Enables the D+ (or potentially D-) pullup. The host will start + * enumerating this gadget when the pullup is active and a VBUS session + * is active (the link is powered). This pullup is always enabled unless + * usb_gadget_disconnect() has been used to disable it. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_connect (struct usb_gadget *gadget) +{ + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + return gadget->ops->pullup (gadget, 1); +} + +/** + * usb_gadget_disconnect - software-controlled disconnect from USB host + * @gadget:the peripheral being disconnected + * + * Disables the D+ (or potentially D-) pullup, which the host may see + * as a disconnect (when a VBUS session is active). Not all systems + * support software pullup controls. + * + * This routine may be used during the gadget driver bind() call to prevent + * the peripheral from ever being visible to the USB host, unless later + * usb_gadget_connect() is called. For example, user mode components may + * need to be activated before the system can talk to hosts. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_disconnect (struct usb_gadget *gadget) +{ + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + return gadget->ops->pullup (gadget, 0); +} + + + +/*-------------------------------------------------------------------------*/ + +/** + * struct usb_gadget_driver - driver for usb 'slave' devices + * @function: String describing the gadget's function + * @speed: Highest speed the driver handles. + * @bind: Invoked when the driver is bound to a gadget, usually + * after registering the driver. + * At that point, ep0 is fully initialized, and ep_list holds + * the currently-available endpoints. + * Called in a context that permits sleeping. + * @setup: Invoked for ep0 control requests that aren't handled by + * the hardware level driver. Most calls must be handled by + * the gadget driver, including descriptor and configuration + * management. The 16 bit members of the setup data are in + * USB byte order. Called in_interrupt; this may not sleep. Driver + * queues a response to ep0, or returns negative to stall. + * @disconnect: Invoked after all transfers have been stopped, + * when the host is disconnected. May be called in_interrupt; this + * may not sleep. Some devices can't detect disconnect, so this might + * not be called except as part of controller shutdown. + * @unbind: Invoked when the driver is unbound from a gadget, + * usually from rmmod (after a disconnect is reported). + * Called in a context that permits sleeping. + * @suspend: Invoked on USB suspend. May be called in_interrupt. + * @resume: Invoked on USB resume. May be called in_interrupt. + * @driver: Driver model state for this driver. + * + * Devices are disabled till a gadget driver successfully bind()s, which + * means the driver will handle setup() requests needed to enumerate (and + * meet "chapter 9" requirements) then do some useful work. + * + * If gadget->is_otg is true, the gadget driver must provide an OTG + * descriptor during enumeration, or else fail the bind() call. In such + * cases, no USB traffic may flow until both bind() returns without + * having called usb_gadget_disconnect(), and the USB host stack has + * initialized. + * + * Drivers use hardware-specific knowledge to configure the usb hardware. + * endpoint addressing is only one of several hardware characteristics that + * are in descriptors the ep0 implementation returns from setup() calls. + * + * Except for ep0 implementation, most driver code shouldn't need change to + * run on top of different usb controllers. It'll use endpoints set up by + * that ep0 implementation. + * + * The usb controller driver handles a few standard usb requests. Those + * include set_address, and feature flags for devices, interfaces, and + * endpoints (the get_status, set_feature, and clear_feature requests). + * + * Accordingly, the driver's setup() callback must always implement all + * get_descriptor requests, returning at least a device descriptor and + * a configuration descriptor. Drivers must make sure the endpoint + * descriptors match any hardware constraints. Some hardware also constrains + * other descriptors. (The pxa250 allows only configurations 1, 2, or 3). + * + * The driver's setup() callback must also implement set_configuration, + * and should also implement set_interface, get_configuration, and + * get_interface. Setting a configuration (or interface) is where + * endpoints should be activated or (config 0) shut down. + * + * (Note that only the default control endpoint is supported. Neither + * hosts nor devices generally support control traffic except to ep0.) + * + * Most devices will ignore USB suspend/resume operations, and so will + * not provide those callbacks. However, some may need to change modes + * when the host is not longer directing those activities. For example, + * local controls (buttons, dials, etc) may need to be re-enabled since + * the (remote) host can't do that any longer; or an error state might + * be cleared, to make the device behave identically whether or not + * power is maintained. + */ +struct usb_gadget_driver { + char *function; + enum usb_device_speed speed; + int (*bind)(struct usb_gadget *); + void (*unbind)(struct usb_gadget *); + int (*setup)(struct usb_gadget *, + const struct usb_ctrlrequest *); + void (*disconnect)(struct usb_gadget *); + void (*suspend)(struct usb_gadget *); + void (*resume)(struct usb_gadget *); + + // FIXME support safe rmmod + struct device_driver driver; +}; + + + +/*-------------------------------------------------------------------------*/ + +/* driver modules register and unregister, as usual. + * these calls must be made in a context that can sleep. + * + * these will usually be implemented directly by the hardware-dependent + * usb bus interface driver, which will only support a single driver. + */ + +/** + * usb_gadget_register_driver - register a gadget driver + * @driver:the driver being registered + * + * Call this in your gadget driver's module initialization function, + * to tell the underlying usb controller driver about your driver. + * The driver's bind() function will be called to bind it to a + * gadget before this registration call returns. It's expected that + * the bind() functions will be in init sections. + * This function must be called in a context that can sleep. + */ +int usb_gadget_register_driver (struct usb_gadget_driver *driver); + +/** + * usb_gadget_unregister_driver - unregister a gadget driver + * @driver:the driver being unregistered + * + * Call this in your gadget driver's module cleanup function, + * to tell the underlying usb controller that your driver is + * going away. If the controller is connected to a USB host, + * it will first disconnect(). The driver is also requested + * to unbind() and clean up any device state, before this procedure + * finally returns. It's expected that the unbind() functions + * will in in exit sections, so may not be linked in some kernels. + * This function must be called in a context that can sleep. + */ +int usb_gadget_unregister_driver (struct usb_gadget_driver *driver); + +/*-------------------------------------------------------------------------*/ + +/* utility to simplify dealing with string descriptors */ + +/** + * struct usb_string - wraps a C string and its USB id + * @id:the (nonzero) ID for this string + * @s:the string, in UTF-8 encoding + * + * If you're using usb_gadget_get_string(), use this to wrap a string + * together with its ID. + */ +struct usb_string { + u8 id; + const char *s; +}; + +/** + * struct usb_gadget_strings - a set of USB strings in a given language + * @language:identifies the strings' language (0x0409 for en-us) + * @strings:array of strings with their ids + * + * If you're using usb_gadget_get_string(), use this to wrap all the + * strings for a given language. + */ +struct usb_gadget_strings { + u16 language; /* 0x0409 for en-us */ + struct usb_string *strings; +}; + +/* put descriptor for string with that id into buf (buflen >= 256) */ +int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf); + +/*-------------------------------------------------------------------------*/ + +/* utility to simplify managing config descriptors */ + +/* write vector of descriptors into buffer */ +int usb_descriptor_fillbuf(void *, unsigned, + const struct usb_descriptor_header **); + +/* build config descriptor from single descriptor vector */ +int usb_gadget_config_buf(const struct usb_config_descriptor *config, + void *buf, unsigned buflen, const struct usb_descriptor_header **desc); + +/*-------------------------------------------------------------------------*/ + +/* utility wrapping a simple endpoint selection policy */ + +extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, + struct usb_endpoint_descriptor *, + struct usb_endpoint_config *, + int numconfigs +) __devinit; + +extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit; + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_USB_GADGET_H */ diff -urN linux-2.6.24.2/Makefile linux-2.6.24.2-vpac1/Makefile --- linux-2.6.24.2/Makefile 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/Makefile 2008-02-22 13:52:46.000000000 +0100 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 24 -EXTRAVERSION = .2 +EXTRAVERSION = .2-vpac1 NAME = Err Metey! A Heury Beelge-a Ret! # *DOCUMENTATION* @@ -190,8 +190,9 @@ # Default value for CROSS_COMPILE is not to prefix executables # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile -ARCH ?= $(SUBARCH) -CROSS_COMPILE ?= +ARCH = arm +CROSS_COMPILE = arm-linux- +#CROSS_COMPILE = arm-none-linux-gnueabi- # Architecture as present in compile.h UTS_MACHINE := $(ARCH) diff -urN linux-2.6.24.2/sound/arm/pxa2xx-ac97.c linux-2.6.24.2-vpac1/sound/arm/pxa2xx-ac97.c --- linux-2.6.24.2/sound/arm/pxa2xx-ac97.c 2008-02-11 06:51:11.000000000 +0100 +++ linux-2.6.24.2-vpac1/sound/arm/pxa2xx-ac97.c 2008-02-22 13:52:46.000000000 +0100 @@ -133,10 +133,12 @@ #ifdef CONFIG_PXA27x /* warm reset broken on Bulverde, so manually keep AC97 reset high */ - pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); +// pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); + pxa_gpio_mode( 95 | GPIO_OUT | GPIO_DFLT_HIGH); udelay(10); GCR |= GCR_WARM_RST; - pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); +// pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); + pxa_gpio_mode(GPIO_AC97_RESET | GPIO_AC97_RST_AF); udelay(500); #else GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN; @@ -148,6 +150,9 @@ __FUNCTION__, gsr_bits); } + pxa2xx_ac97_write(ac97, 0x6a, 0x0050); + pxa2xx_ac97_write(ac97, 0x6c, 0x0030); + GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); GCR |= GCR_SDONE_IE|GCR_CDONE_IE; } @@ -335,7 +340,9 @@ pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); #ifdef CONFIG_PXA27x /* Use GPIO 113 as AC97 Reset on Bulverde */ - pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); +// pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); + pxa_gpio_mode(GPIO_AC97_RESET | GPIO_AC97_RST_AF); + pxa_gpio_mode(GPIO_AC97_SYSCLK | GPIO_AC97_SYSCLK_AF); #endif pxa_set_cken(CKEN_AC97, 1);