diff options
author | Koen Kooi <koen@openembedded.org> | 2007-04-23 14:34:37 +0000 |
---|---|---|
committer | Koen Kooi <koen@openembedded.org> | 2007-04-23 14:34:37 +0000 |
commit | 0e8d04af1e7063df333680d6ac16ce69ff3bf968 (patch) | |
tree | 1f7a76b124194fce461c323175cd2cb72f4c7e47 | |
parent | 81654790f772904aef4021434d4f97febd4199d0 (diff) |
linux-ezx: add experimental 2.6.20.7 kernel
* the kernel is slightly to big, but people will use boot_usb anyway
23 files changed, 14551 insertions, 0 deletions
diff --git a/packages/linux/linux-ezx-2.6.20.7/.mtn2git_empty b/packages/linux/linux-ezx-2.6.20.7/.mtn2git_empty new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/.mtn2git_empty diff --git a/packages/linux/linux-ezx-2.6.20.7/defconfig-a780 b/packages/linux/linux-ezx-2.6.20.7/defconfig-a780 new file mode 100644 index 0000000000..04735c6136 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/defconfig-a780 @@ -0,0 +1,1352 @@ + + + + + +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" +"http://www.w3.org/TR/REC-html40/loose.dtd"> +<!-- ViewCVS - http://viewcvs.sourceforge.net/ +by Greg Stein - mailto:gstein@lyra.org --> +<html> +<head> +<title>svn.openezx.org Repository - markup - svn.openezx.org: branches/kernel-2.6.20.7-patches/defconfig-a780</title> +<meta name="generator" content="ViewCVS 1.0-dev"> +<link rel="stylesheet" href="/viewcvs/styles.css" type="text/css"> +</head> +<body> +<div class="vc_navheader"> +<table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tr> +<td align="left"><a href="/cgi-bin/viewcvs.cgi/?rev=1981#dirlist">[svn.openezx.org]</a> / <a href="/cgi-bin/viewcvs.cgi/branches/?rev=1981#dirlist">branches</a> / <a href="/cgi-bin/viewcvs.cgi/branches/kernel-2.6.20.7-patches/?rev=1981#dirlist">kernel-2.6.20.7-patches</a> / defconfig-a780</td> +<td align="right"> + +<form method=get action="/cgi-bin/viewcvs.cgi/"> + +<b>Project Root:</b> +<select name="root" onchange="submit()"> + + + + + + + + + + + + + + + + + + + + + + +<optgroup label="CVS Repositories"><option>cvs</option></optgroup> + + +<optgroup label="Subversion Repositories"><option selected>svn.openezx.org</option></optgroup> + +</select> +<input type=submit value="Go"> +</form> + +</td> +</tr> +</table> +</div> +<h1>svn.openezx.org: branches/kernel-2.6.20.7-patches/defconfig-a780</h1> + +<div class="vc_summary"> +File: <a href="/cgi-bin/viewcvs.cgi/?rev=1981#dirlist">[svn.openezx.org]</a> / <a href="/cgi-bin/viewcvs.cgi/branches/?rev=1981#dirlist">branches</a> / <a href="/cgi-bin/viewcvs.cgi/branches/kernel-2.6.20.7-patches/?rev=1981#dirlist">kernel-2.6.20.7-patches</a> / defconfig-a780 +(<a href="/cgi-bin/viewcvs.cgi/*checkout*/branches/kernel-2.6.20.7-patches/defconfig-a780?rev=1981"><b>download</b></a>) + +<br> + +Revision: <b>1981</b>, +<i>Sun Apr 22 20:32:25 2007 UTC</i> (16 hours, 45 minutes ago) by <i>wyrm</i> + + + + + +<br>File size: 25011 byte(s) + + +<pre class="vc_log">latest .config + +</pre> + +</div> +<pre># +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.20.7 +# Sun Apr 22 15:03:36 2007 +# +CONFIG_ARM=y +# CONFIG_GENERIC_TIME is not set +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=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_ARCH_MTD_XIP=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="-ezxdev" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=m +CONFIG_IOSCHED_CFQ=m +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# 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_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_L7200 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_OMAP is not set + +# +# Intel PXA2xx Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_MACH_LOGICPD_PXA270 is not set +# CONFIG_MACH_MAINSTONE is not set +# CONFIG_ARCH_PXA_IDP is not set +# CONFIG_PXA_SHARPSL is not set +# CONFIG_MACH_TRIZEPS4 is not set +CONFIG_PXA_EZX=y +# CONFIG_PXA_EZX_E680 is not set +CONFIG_PXA_EZX_A780=y +# CONFIG_PXA_EZX_E2 is not set +CONFIG_PXA27x=y +CONFIG_PXA_SSP=y + +# +# 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=y +# CONFIG_CPU_DCACHE_DISABLE is not set +CONFIG_IWMMXT=y +CONFIG_XSCALE_PMU=y + +# +# Bus support +# + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +# CONFIG_PREEMPT is not set +CONFIG_NO_IDLE_HZ=y +CONFIG_HZ=100 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +# 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_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="console=tty1 noinitrd root=/dev/mmcblk0p2 rootfstype=ext3 ip=169.254.1.11:169.254.1.10:169.254.1.10:255.255.255.254:ezx:usb0:off debug mem=32M@0xA0000000 mem=16M@0xAC000000" +# CONFIG_XIP_KERNEL is not set + +# +# 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=m +CONFIG_BINFMT_MISC=m + +# +# Power management options +# +# CONFIG_PM is not set +# CONFIG_APM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# 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 + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# 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 + +# +# QoS and/or fair queueing +# +# 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=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCIUSB is not set +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=m +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +CONFIG_CONNECTOR=m + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# 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 + +# +# 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_OBSOLETE_CHIPS is not set +CONFIG_MTD_XIP=y + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_SHARP_SL is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Network device support +# +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# 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 + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS 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_TSDEV=y +CONFIG_INPUT_TSDEV_SCREEN_X=240 +CONFIG_INPUT_TSDEV_SCREEN_Y=320 +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 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 is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_RAW 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=y +CONFIG_LEGACY_PTY_COUNT=8 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# 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_PXA=y +# CONFIG_I2C_PXA_SLAVE is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 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_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=y +CONFIG_SPI_DEBUG=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +CONFIG_SPI_PXA2XX=y + +# +# SPI Protocol Masters +# + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# LED devices +# +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set +# CONFIG_USB_DABUSB is not set + +# +# Graphics support +# +# CONFIG_FIRMWARE_EDID is not set +CONFIG_FB=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# 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 +# CONFIG_FB_S1D13XXX is not set +CONFIG_FB_PXA=y +CONFIG_FB_PXA_PARAMETERS=y +# CONFIG_FB_MBX is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FONTS=y +# CONFIG_FONT_8x8 is not set +# CONFIG_FONT_8x16 is not set +# 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=y +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +CONFIG_SOUND=y + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS 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_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_AC97 is not set + +# +# USB devices +# +# CONFIG_SND_USB_AUDIO is not set + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# HID Devices +# +CONFIG_HID=y + +# +# USB support +# +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 is not set +# CONFIG_USB_BANDWIDTH is not set +# 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 is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_SL811_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_LIBUSUAL is not set + +# +# USB Input Devices +# +# CONFIG_USB_HID is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_TOUCHSCREEN is not set +# CONFIG_USB_YEALINK is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_ATI_REMOTE2 is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set + +# +# 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_MII is not set +# CONFIG_USB_USBNET is not set +CONFIG_USB_MON=y + +# +# 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_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 + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_AT91 is not set +CONFIG_USB_GADGET_DUMMY_HCD=y +CONFIG_USB_DUMMY_HCD=y +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +CONFIG_USB_ETH=y +# CONFIG_USB_ETH_RNDIS is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_BLOCK=y +CONFIG_MMC_PXA=y +# CONFIG_MMC_TIFM_SD is not set + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set + +# +# RTC drivers +# +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_M48T86 is not set +CONFIG_RTC_DRV_SA1100=y +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# File systems +# +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# 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=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# 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=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +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_RAMFS=y +# 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 is not set +CONFIG_CRAMFS=y +# 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 + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +CONFIG_NFSD_TCP=y +# CONFIG_ROOT_NFS is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME 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=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_PI_LIST=y +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_RWSEMS=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FRAME_POINTER=y +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=m +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_PLIST=y +CONFIG_IOMAP_COPY=y +</pre> + +<hr noshade> +<table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tr> +<td align="left"> +<address><a href="mailto:svn-admin@openezx.org">CVS Admin</a></address><br /> +Powered by <a href="http://viewcvs.sourceforge.net/">ViewCVS 1.0-dev</a> +</td> +<td align="right"> +<img src="/doc/viewcvs/images/logo.png" alt="(Powered by ViewCVS)" border="0" +width="128" height="48" /><br /> +<h3><a target="_blank" href="/viewcvs/help_rootview.html">ViewCVS and CVS Help</a></h3> +</td> +</tr> +</table> +</body> +</html> + diff --git a/packages/linux/linux-ezx-2.6.20.7/ezx-core.patch b/packages/linux/linux-ezx-2.6.20.7/ezx-core.patch new file mode 100644 index 0000000000..3b9877ce83 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/ezx-core.patch @@ -0,0 +1,1120 @@ +Index: linux-2.6.20.7/arch/arm/boot/compressed/head-xscale.S +=================================================================== +--- linux-2.6.20.7.orig/arch/arm/boot/compressed/head-xscale.S 2007-04-21 22:31:54.000000000 -0300 ++++ linux-2.6.20.7/arch/arm/boot/compressed/head-xscale.S 2007-04-21 22:32:53.000000000 -0300 +@@ -53,3 +53,6 @@ + str r1, [r0, #0x18] + #endif + ++#ifdef CONFIG_ARCH_EZX ++ mov r7, #MACH_TYPE_EZX ++#endif +Index: linux-2.6.20.7/arch/arm/mach-pxa/Kconfig +=================================================================== +--- linux-2.6.20.7.orig/arch/arm/mach-pxa/Kconfig 2007-04-21 22:31:54.000000000 -0300 ++++ linux-2.6.20.7/arch/arm/mach-pxa/Kconfig 2007-04-22 01:33:15.000000000 -0300 +@@ -37,6 +37,10 @@ + bool "Keith und Koep Trizeps4 DIMM-Module" + select PXA27x + ++config PXA_EZX ++ bool "Motorola EZX Platform" ++ select PXA_SSP ++ + endchoice + + if PXA_SHARPSL +@@ -71,6 +75,27 @@ + + endif + ++if PXA_EZX ++ ++choice ++ prompt "Select target EZX device" ++ ++config PXA_EZX_E680 ++ bool "Motorola E680 GSM Phone" ++ select PXA27x ++ ++config PXA_EZX_A780 ++ bool "Motorola A780 GSM Phone" ++ select PXA27x ++ ++config PXA_EZX_E2 ++ bool "Motorola E2 GSM Phone" ++ select PXA27x ++ ++endchoice ++ ++endif ++ + endmenu + + config MACH_POODLE +@@ -144,4 +169,5 @@ + tristate + help + Enable support for PXA2xx SSP ports ++ + endif +Index: linux-2.6.20.7/arch/arm/mach-pxa/Makefile +=================================================================== +--- linux-2.6.20.7.orig/arch/arm/mach-pxa/Makefile 2007-04-21 22:31:54.000000000 -0300 ++++ linux-2.6.20.7/arch/arm/mach-pxa/Makefile 2007-04-22 01:33:17.000000000 -0300 +@@ -18,6 +18,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_PXA_EZX) += ezx.o ezx_lcd.o ezx_ssp.o + + # Support for blinky lights + led-y := leds.o +Index: linux-2.6.20.7/arch/arm/mach-pxa/ezx.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/arch/arm/mach-pxa/ezx.c 2007-04-22 01:33:17.000000000 -0300 +@@ -0,0 +1,379 @@ ++/* ++ * linux/arch/arm/mach-ezx/a780.c ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Zhuang Xiaofan ++ * Created: Nov 25, 2003 ++ * Copyright: Motorola Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++#include <linux/bitops.h> ++#include <linux/apm_bios.h> ++#include <linux/platform_device.h> ++#include <linux/input.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/ohci.h> ++#include <asm/arch/pxa-regs.h> ++ ++#include "ezx.h" ++#include "generic.h" ++#include <linux/tty.h> ++#include <linux/apm_bios.h> ++ ++ ++extern void usb_send_readurb(void); ++extern int ezx_ssp_set_machinfo(struct ezxssp_machinfo *); ++//FIXME extern void pm_do_poweroff(void); ++ ++/* BP Handshake */ ++#define FIRST_STEP 2 ++#define LAST_STEP 3 ++#define BP_RDY_TIMEOUT 0x000c0000 ++ ++/* check power down condition */ ++inline void check_power_off(void) ++{ ++ if (!(GPIO_is_high(GPIO_BB_WDI2))) { ++#ifdef CONFIG_PM ++//FIXME pm_do_poweroff(); ++#endif ++ } ++} ++ ++/* SSP */ ++struct platform_device ezxssp_device = { ++ .name = "ezx-ssp", ++ .id = -1, ++}; ++ ++struct ezxssp_machinfo ezx_ssp_machinfo = { ++ .port = 1, ++ .cs_pcap = GPIO_SPI_CE, ++ .clk_pcap = 1, ++}; ++ ++ ++/* OHCI Controller */ ++ ++static int ezx_ohci_init(struct device *dev) ++{ ++ /* for A780 support (connected with Neptune) */ ++ pxa_gpio_mode(GPIO30_USB_P3_2); /* GPIO30 - USB_P3_2/ICL_TXENB */ ++ pxa_gpio_mode(GPIO31_USB_P3_6); /* GPIO31 - USB_P3_6/ICL_VPOUT */ ++ pxa_gpio_mode(GPIO90_USB_P3_5); /* GPIO90 - USB_P3_5/ICL_VPIN */ ++ pxa_gpio_mode(GPIO91_USB_P3_1); /* GPIO91 - USB_P3_1/ICL_XRXD */ ++ pxa_gpio_mode(GPIO56_USB_P3_4); /* GPIO56 - USB_P3_4/ICL_VMOUT */ ++ pxa_gpio_mode(GPIO113_USB_P3_3);/* GPIO113 - USB_P3_3/ICL_VMIN */ ++ UP3OCR = 0x00000002; ++ ++ UHCHR = UHCHR & ~(UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE); ++ ++ return 0; ++} ++ ++static struct pxaohci_platform_data ezx_ohci_platform_data = { ++ .port_mode = PMM_NPS_MODE, ++ .init = ezx_ohci_init, ++}; ++ ++static int step = FIRST_STEP; ++void handshake(void) ++{ ++ /* step 1: check MCU_INT_SW or BP_RDY is low (now it is checked in apboot) */ ++ if (step == 1) { ++ int timeout = BP_RDY_TIMEOUT; ++ ++ /* config MCU_INT_SW, BP_RDY as input */ ++ GPDR(GPIO_MCU_INT_SW) &= ~GPIO_bit(GPIO_MCU_INT_SW); ++ GPDR(GPIO_BP_RDY) &= ~GPIO_bit(GPIO_BP_RDY); ++ ++ while ( timeout -- ) { ++ if ( (!(GPIO_is_high(GPIO_MCU_INT_SW))) ++ || (!(GPIO_is_high(GPIO_BP_RDY))) ) { ++ step ++; ++ break; ++ } ++ ++ check_power_off(); ++ } ++ } ++ ++ /* step 2: wait BP_RDY is low */ ++ if (step == 2) { ++ if (!(GPIO_is_high(GPIO_BP_RDY))) { ++ ++ /* config MCU_INT_SW as output */ ++ pxa_gpio_mode(GPIO_MCU_INT_SW | GPIO_OUT); ++ clr_GPIO(GPIO_MCU_INT_SW); ++ ++ step ++; ++ } ++ } ++ ++ /* step 3: wait BP_RDY is high */ ++ if (step == 3) { ++ if (GPIO_is_high(GPIO_BP_RDY)) { ++ step ++; ++ //FIXME delay_bklight(); ++ set_GPIO(GPIO_MCU_INT_SW); ++ } ++ } ++} ++ ++#ifdef CONFIG_APM ++static unsigned long idle_limit = 0; ++int pm_handle_irq(int irq) ++{ ++ ++ //FIXME: extern unsigned long idle_limit; ++ //FIXME: extern int can_idle, can_sleep; ++ static unsigned long tmp_jiffy; /* for temporary store of jiffies */ ++ ++ /* ++ * if idle_limit is zero, never enter idle. ++ * if not OS timer, reset idle timer count ++ */ ++ if (idle_limit == 0) { ++ tmp_jiffy = jiffies; ++ return irq; ++ } ++#if 0 ++ if (irq != IRQ_OST0) { ++ tmp_jiffy = jiffies; ++ can_idle = 0; ++ can_sleep = 0; ++ } else if (jiffies > tmp_jiffy + idle_limit) { ++ ++ /* ++ * I think this is enough to prevent from reentering here ++ * due to jiffies will be stoped ++ */ ++ tmp_jiffy = jiffies; ++ ++ /* if pm idle timer expired, queue event */ ++ apm_queue_event(KRNL_PROC_INACT); ++ can_idle = 1; ++ } ++#endif ++ ++ return irq; ++} ++ ++irqreturn_t bp_wdi_intr(int irq, void *dev_id) ++{ ++//FIXME apm_queue_event(KRNL_BP_WDI); ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction bp_wdi_irq = { ++ .name = "BP wdi", ++ .handler = &bp_wdi_intr, ++}; ++#endif ++ ++int handshake_pass(void) ++{ ++ return (step > LAST_STEP); ++} ++ ++static irqreturn_t bp_rdy_intr(int irq, void *dev_id) ++{ ++ static int usbipc_ready = 0; ++ ++ if (!usbipc_ready) { ++ handshake(); ++ if (handshake_pass()) { ++ disable_irq(IRQ_GPIO(GPIO_BB_WDI2)); ++ ++ /* set bp_rdy handle for usb ipc */ ++ set_irq_type(GPIO_BP_RDY, IRQT_FALLING); ++ usbipc_ready = 1; ++ } ++ } else ++ // FIXME usb_send_readurb(); ++ {} ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction bp_rdy_irq = { ++ .name = "BP rdy", ++ .handler = bp_rdy_intr, ++}; ++ ++static irqreturn_t bp_wdi2_intr(int irq, void *dev_id) ++{ ++#ifdef CONFIG_PM ++//FIXME pm_do_poweroff(); ++#endif ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction bp_wdi2_irq = { ++ .name = "BP wdi2", ++ .handler = bp_wdi2_intr, ++}; ++ ++ ++static struct resource ezx_bp_resources[] = { ++ [0] = { ++ .start = GPIO_BP_RDY, ++ .end = GPIO_BP_RDY, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [1] = { ++ .start = GPIO_BB_WDI2, ++ .end = GPIO_BB_WDI2, ++ .flags = IORESOURCE_IRQ, ++ }, ++#ifdef CONFIG_APM ++ [2] = { ++ .start = GPIO_BB_WDI, ++ .end = GPIO_BB_WDI, ++ .flags = IORESOURCE_IRQ, ++ }, ++#endif ++}; ++ ++static struct platform_device ezx_bp_device = { ++ .name = "ezx-bp", ++ .dev = { ++ //.parent = ++ //.platform_data = ++ }, ++ .id = -1, ++ .num_resources = ARRAY_SIZE(ezx_bp_resources), ++ .resource = ezx_bp_resources, ++}; ++ ++static void __init ezx_init_gpio_irq(void) ++{ ++#ifdef CONFIG_APM ++ set_irq_type(GPIO_BB_WDI, IRQT_FALLING); ++ setup_irq(IRQ_GPIO(GPIO_BB_WDI), &bp_wdi_irq); ++#endif ++ set_irq_type(GPIO_BP_RDY, IRQT_BOTHEDGE); ++ setup_irq(IRQ_GPIO(GPIO_BP_RDY), &bp_rdy_irq); ++ ++ set_irq_type(GPIO_BB_WDI2, IRQT_FALLING); ++ setup_irq(IRQ_GPIO(GPIO_BB_WDI2), &bp_wdi2_irq); ++} ++ ++static void __init a780_init_irq(void) ++{ ++ pxa_init_irq(); ++ ++ /* init ezx specfic gpio irq */ ++ ezx_init_gpio_irq(); ++ ++ check_power_off(); ++ handshake(); ++ if (handshake_pass()) { ++ disable_irq(IRQ_GPIO(GPIO_BP_RDY)); ++ disable_irq(IRQ_GPIO(GPIO_BB_WDI2)); ++ } ++} ++ ++static struct platform_device *devices[] __initdata = { ++ &ezxssp_device, ++ &ezx_bp_device, ++}; ++ ++static void __init a780_init(void) ++{ ++//FIXME CKEN = CKEN9_OSTIMER | CKEN22_MEMC | CKEN5_STUART; ++ ++ ezx_ssp_set_machinfo(&ezx_ssp_machinfo); ++ ++ /* set BB_RESET PIN out put high */ ++ pxa_gpio_mode(GPIO_BB_RESET|GPIO_OUT); ++ set_GPIO(GPIO_BB_RESET); ++ ++ pxa_gpio_mode(GPIO_ICL_FFRXD_MD); ++ pxa_gpio_mode(GPIO_ICL_FFTXD_MD); ++ pxa_gpio_mode(GPIO_ICL_FFCTS_MD); ++ pxa_gpio_mode(GPIO_ICL_FFRTS_MD); ++ ++ pxa_gpio_mode(GPIO42_BTRXD_MD); ++ pxa_gpio_mode(GPIO43_BTTXD_MD); ++ pxa_gpio_mode(GPIO44_BTCTS_MD); ++ pxa_gpio_mode(GPIO45_BTRTS_MD); ++ ++ /* clear EMU MUX1/MUX2 (low) to close the audio path to EMU */ ++ pxa_gpio_mode(GPIO_EMU_MUX1|GPIO_OUT); ++ clr_GPIO(GPIO_EMU_MUX1); ++ pxa_gpio_mode(GPIO_EMU_MUX2|GPIO_OUT); ++ clr_GPIO(GPIO_EMU_MUX2); ++ ++#if defined(CONFIG_PXA_EZX_E680) ++ pxa_gpio_mode(GPIO46_STRXD_MD); ++ pxa_gpio_mode(GPIO47_STTXD_MD); ++ ++ /* setup sleep mode values */ ++ PWER = 0xc000f803; // disable usb 0xdc00f803; ++ PFER = 0x0000f803; ++ PRER = 0x00001802; ++ // keypad wakeup (PKWR,PGSR3) should be in keypad.c ++ PGSR0 = 0x00000010; ++ PGSR1 = 0x02800000; ++ PGSR2 = 0x00040000; ++ PGSR3 = 0x00000000; ++ PCFR = PCFR_DC_EN | PCFR_FS | PCFR_FP | PCFR_OPDE; ++ PSLR = 0x05800f00; ++ ++#elif defined(CONFIG_PXA_EZX_A780) ++ ++ /* Standard UART */ ++ pxa_gpio_mode(GPIO46_STRXD_MD); ++ pxa_gpio_mode(GPIO47_STTXD_MD); ++ ++ /* setup sleep mode values */ ++ PWER = 0xc0007803; // disable usb, GPIO15 NC ++ PFER = 0x00007803; ++ PRER = 0x00001802; ++ // keypad wakeup (PKWR,PGSR3) should be in keypad.c ++ PGSR0 = 0x00000010; ++ PGSR1 = 0x02800000; ++ PGSR2 = 0x00040000; ++ PGSR3 = 0x00000008; ++ PCFR = PCFR_DC_EN | PCFR_FS | PCFR_FP | PCFR_OPDE; ++ PSLR = 0x05800f00; ++ ++#endif ++ pxa_set_ohci_info(&ezx_ohci_platform_data); ++ ++ platform_add_devices(devices, ARRAY_SIZE(devices)); ++ ++} ++ ++MACHINE_START(EZX, "Motorola Ezx Platform") ++ /* Maintainer: Harald Welte <laforge@gnumonks.org> */ ++ .phys_io = 0x40000000, ++ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, ++ .boot_params = 0xa0000100, ++ .map_io = pxa_map_io, ++ .init_irq = a780_init_irq, ++ .timer = &pxa_timer, ++ .init_machine = a780_init, ++MACHINE_END +Index: linux-2.6.20.7/include/asm-arm/arch-pxa/ezx.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/include/asm-arm/arch-pxa/ezx.h 2007-04-21 22:32:53.000000000 -0300 +@@ -0,0 +1,225 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/ezx.h ++ * ++ * Specific macro defines for Motorola Ezx Development Platform ++ * ++ * Author: Zhuang Xiaofan ++ * Created: Nov 25, 2003 ++ * Copyright: Motorola Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/* support E680 p3 and ealier PCB */ ++//#define E680_P3_AND_EARLY ++ ++#define GPIO_is_high(x) (GPLR(x) & GPIO_bit(x)) ++#define set_GPIO(x) (GPSR(x) = GPIO_bit(x)) ++#define clr_GPIO(x) (GPCR(x) = GPIO_bit(x)) ++ ++/* ++ * Flags in memory for sleep use ++ */ ++#define FLAG_ADDR PHYS_OFFSET ++#define RESUME_ADDR (PHYS_OFFSET + 4) ++#define BPSIG_ADDR (PHYS_OFFSET + 8) ++ ++#define USER_OFF_FLAG 0x5a5a5a5a ++#define SLEEP_FLAG 0x6b6b6b6b ++#define OFF_FLAG 0x7c7c7c7c ++#define REFLASH_FLAG 0x0C1D2E3F ++#define PASS_THRU_FLAG 0x12345678 ++ ++#define WDI_FLAG 0xbb00dead ++#define NO_FLAG 0xaa00dead ++ ++/* ++ * GPIO control pin, have to change when hardware lock down ++ */ ++ ++#ifdef E680_P3_AND_EARLY ++ ++/* shakehand with BP's PIN */ ++#define GPIO_BP_RDY 0 /* BP_RDY */ ++#define GPIO_BB_WDI 13 /* BB_WDI */ ++#define GPIO_BB_WDI2 3 /* BB_WDI2 */ ++#define GPIO_BB_RESET 57 /* BB_RESET */ ++#define GPIO_MCU_INT_SW 115 /* MCU_INT_SW */ ++#define GPIO_TC_MM_EN 89 /* TC_MM_EN */ ++ ++/* control PCAP direct PIN */ ++#define GPIO_WDI_AP 4 /* WDI_AP */ ++#define GPIO_SYS_RESTART 55 /* restart PCAP power */ ++#define GPIO_AP_STANDBY 28 /* make pcap enter standby mode */ ++ ++/* communicate with PCAP's PIN */ ++#define GPIO_PCAP_SEC_INT 1 /* PCAP interrupt PIN to AP */ ++#define GPIO_SPI_CLK 23 /* PCAP SPI port clock */ ++#define GPIO_SPI_CE 24 /* PCAP SPI port SSPFRM */ ++#define GPIO_SPI_MOSI 25 /* PCAP SPI port SSPTXD */ ++#define GPIO_SPI_MISO 26 /* PCAP SPI port SSPRXD */ ++ ++/* blue tooth control PIN */ ++#define GPIO_BT_WAKEUP 2 /* AP wake up bluetooth module */ ++#define GPIO_BT_HOSTWAKE 14 /* bluetooth module wake up Ap module */ ++#define GPIO_BT_RESET 56 /* AP reset bluetooth module */ ++ ++/* control LCD high - OFF low -- ON */ ++#define GPIO_LCD_OFF 116 /* control LCD */ ++ ++/* FFUART PIN */ ++#define GPIO_ICL_FFRXD_MD (34 | GPIO_ALT_FN_1_IN) ++#define GPIO_ICL_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) ++#define GPIO_ICL_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) ++#define GPIO_ICL_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) ++ ++#elif defined(A780_P1_AND_EARLY) ++ ++/* shakehand with BP's PIN */ ++#define GPIO_BP_RDY 0 /* BP_RDY */ ++#define GPIO_BB_WDI 13 /* BB_WDI */ ++#define GPIO_BB_WDI2 3 /* BB_WDI2 */ ++#define GPIO_BB_RESET 82 /* BB_RESET */ ++#define GPIO_MCU_INT_SW 57 /* MCU_INT_SW */ ++#define GPIO_TC_MM_EN 89 /* TC_MM_EN */ ++ ++/* control PCAP direct PIN */ ++#define GPIO_WDI_AP 4 /* WDI_AP */ ++#define GPIO_SYS_RESTART 55 /* restart PCAP power */ ++#define GPIO_AP_STANDBY 28 /* make pcap enter standby mode */ ++ ++/* communicate with PCAP's PIN */ ++#define GPIO_PCAP_SEC_INT 1 /* PCAP interrupt PIN to AP */ ++#define GPIO_SPI_CLK 29 /* PCAP SPI port clock */ ++#define GPIO_SPI_CE 24 /* PCAP SPI port SSPFRM */ ++#define GPIO_SPI_MOSI 25 /* PCAP SPI port SSPTXD */ ++#define GPIO_SPI_MISO 26 /* PCAP SPI port SSPRXD */ ++ ++/* blue tooth control PIN */ ++#define GPIO_BT_WAKEUP 2 /* AP wake up bluetooth module */ ++#define GPIO_BT_HOSTWAKE 14 /* bluetooth module wake up Ap module */ ++#define GPIO_BT_RESET 56 /* AP reset bluetooth module */ ++ ++/* control LCD high - OFF low -- ON */ ++#define GPIO_LCD_OFF 116 /* control LCD */ ++ ++/* FFUART PIN */ ++#define GPIO_ICL_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) ++#define GPIO_ICL_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) ++#define GPIO_ICL_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) ++#define GPIO_ICL_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) ++ ++#else ++ ++/* shakehand with BP's PIN */ ++#define GPIO_BP_RDY 0 /* BP_RDY */ ++#define GPIO_BB_WDI 13 /* BB_WDI */ ++#define GPIO_BB_WDI2 3 /* BB_WDI2 */ ++#define GPIO_BB_RESET 82 /* BB_RESET */ ++#define GPIO_MCU_INT_SW 57 /* MCU_INT_SW */ ++#define GPIO_TC_MM_EN 99 /* TC_MM_EN */ ++ ++/* control PCAP direct PIN */ ++#define GPIO_WDI_AP 4 /* WDI_AP */ ++#define GPIO_SYS_RESTART 55 /* restart PCAP power */ ++//#define GPIO_AP_STANDBY 28 /* make pcap enter standby mode */ ++ ++/* communicate with PCAP's PIN */ ++#define GPIO_PCAP_SEC_INT 1 /* PCAP interrupt PIN to AP */ ++#define GPIO_SPI_CLK 29 /* PCAP SPI port clock */ ++#define GPIO_SPI_CE 24 /* PCAP SPI port SSPFRM */ ++#define GPIO_SPI_MOSI 25 /* PCAP SPI port SSPTXD */ ++#define GPIO_SPI_MISO 26 /* PCAP SPI port SSPRXD */ ++ ++/* blue tooth control PIN */ ++#define GPIO_BT_WAKEUP 28 /* AP wake up bluetooth module */ ++#define GPIO_BT_HOSTWAKE 14 /* AP wake up bluetooth module */ ++#define GPIO_BT_RESET 48 /* AP reset bluetooth module */ ++ ++/* control LCD high - OFF low -- ON */ ++#define GPIO_LCD_OFF 116 /* control LCD */ ++ ++/* FFUART PIN */ ++#define GPIO_ICL_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) ++#define GPIO_ICL_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) ++#define GPIO_ICL_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) ++#define GPIO_ICL_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) ++ ++#endif ++/* ++ * ezx platform, wake up source edge detect bit ++ */ ++#define PEDR_INT_SEC 1 ++ ++#define GPIO_FLIP_PIN 12 ++/*E680 screen lock button*/ ++ ++#define GPIO_LOCK_SCREEN_PIN GPIO_FLIP_PIN ++ ++/* MMC interface */ ++#define GPIO_MMC_DETECT 11 ++#define GPIO_MMC_CLK 32 ++#define GPIO_MMC_DATA0 92 ++#define GPIO_MMC_WP 107 ++#define GPIO_MMC_DATA1 109 ++#define GPIO_MMC_DATA2 110 ++#define GPIO_MMC_DATA3 111 ++#define GPIO_MMC_CMD 112 ++ ++/* interface function */ ++#define GPIO_MMC_CLK_MD (GPIO_MMC_CLK | GPIO_ALT_FN_2_OUT) ++#define GPIO_MMC_DATA0_MD (GPIO_MMC_DATA0 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) ++#define GPIO_MMC_DATA1_MD (GPIO_MMC_DATA1 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) ++#define GPIO_MMC_DATA2_MD (GPIO_MMC_DATA2 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) ++#define GPIO_MMC_DATA3_MD (GPIO_MMC_DATA3 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) ++ ++#define GPIO_MMC_CMD_MD (GPIO_MMC_CMD | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) ++ ++/* EMU GPIO 119 ---MUX2 120 --- MUX1 */ ++#define GPIO_EMU_MUX1 120 ++#define GPIO_EMU_MUX2 119 ++#define GPIO_SNP_INT_CTL 86 ++#define GPIO_SNP_INT_IN 87 ++ ++ ++/* audio related pins */ ++#define AP_13MHZ_OUTPUT_PIN 9 ++ ++#ifdef CONFIG_ARCH_EZX_E680 ++#define GPIO_VA_SEL_BUL 79 ++#define GPIO_FLT_SEL_BUL 80 /* out filter select pin */ ++#define GPIO_MIDI_RESET 78 /* GPIO used by MIDI chipset */ ++#define GPIO_MIDI_CS 33 ++#define GPIO_MIDI_IRQ 15 ++#define GPIO_MIDI_NPWE 49 ++#define GPIO_MIDI_RDY 18 ++#endif ++ ++#ifdef CONFIG_ARCH_EZX_A780 ++#define GPIO_HW_ATTENUATE_A780 96 /* hw noise attenuation be used or bypassed, for receiver or louderspeaker mode */ ++#endif ++ ++ ++/* bp status pin */ ++#define GPIO_BP_STATE 41 ++ ++/* define usb related pin */ ++#define GPIO34_TXENB 34 ++#define GPIO35_XRXD 35 ++#define GPIO36_VMOUT 36 ++#define GPIO39_VPOUT 39 ++#define GPIO40_VPIN 40 ++#define GPIO53_VMIN 53 ++ ++/* USB client 6 pin defination */ ++#define GPIO34_TXENB_MD (GPIO34_TXENB | GPIO_ALT_FN_1_OUT) ++#define GPIO35_XRXD_MD (GPIO35_XRXD | GPIO_ALT_FN_2_IN ) ++#define GPIO36_VMOUT_MD (GPIO36_VMOUT | GPIO_ALT_FN_1_OUT) ++#define GPIO39_VPOUT_MD (GPIO39_VPOUT | GPIO_ALT_FN_1_OUT) ++#define GPIO40_VPIN_MD (GPIO40_VPIN | GPIO_ALT_FN_3_IN ) ++#define GPIO53_VMIN_MD (GPIO53_VMIN | GPIO_ALT_FN_2_IN ) ++ ++#define GPIO53_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) ++ +Index: linux-2.6.20.7/include/asm-arm/arch-pxa/pxa-regs.h +=================================================================== +--- linux-2.6.20.7.orig/include/asm/arch/pxa-regs.h 2007-04-21 22:31:54.000000000 -0300 ++++ linux-2.6.20.7/include/asm-arm/arch-pxa/pxa-regs.h 2007-04-21 22:32:53.000000000 -0300 +@@ -854,6 +854,8 @@ + #define UP2OCR_HXOE (1 << 17) /* Host Port 2 Transceiver Output Enable */ + #define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */ + ++#define UP3OCR __REG(0x40600024) /* USB Port 3 Output Control register */ ++ + #define UDCCSN(x) __REG2(0x40600100, (x) << 2) + #define UDCCSR0 __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */ + #define UDCCSR0_SA (1 << 7) /* Setup Active */ +@@ -1257,6 +1259,7 @@ + #define GPIO33_nCS_5 33 /* chip select 5 */ + #define GPIO34_FFRXD 34 /* FFUART receive */ + #define GPIO34_MMCCS0 34 /* MMC Chip Select 0 */ ++#define GPIO34_USB_P2_2 34 /* USB Port2 Pin 2 */ + #define GPIO35_FFCTS 35 /* FFUART Clear to send */ + #define GPIO36_FFDCD 36 /* FFUART Data carrier detect */ + #define GPIO37_FFDSR 37 /* FFUART data set ready */ +@@ -1370,6 +1373,7 @@ + #define GPIO18_RDY_MD (18 | GPIO_ALT_FN_1_IN) + #define GPIO19_DREQ1_MD (19 | GPIO_ALT_FN_1_IN) + #define GPIO20_DREQ0_MD (20 | GPIO_ALT_FN_1_IN) ++#define GPIO22_SCLK2_MD (22 | GPIO_ALT_FN_3_IN) + #define GPIO23_SCLK_MD (23 | GPIO_ALT_FN_2_OUT) + #define GPIO24_SFRM_MD (24 | GPIO_ALT_FN_2_OUT) + #define GPIO25_STXD_MD (25 | GPIO_ALT_FN_2_OUT) +@@ -1380,23 +1384,33 @@ + #define GPIO28_BITCLK_OUT_I2S_MD (28 | GPIO_ALT_FN_1_OUT) + #define GPIO29_SDATA_IN_AC97_MD (29 | GPIO_ALT_FN_1_IN) + #define GPIO29_SDATA_IN_I2S_MD (29 | GPIO_ALT_FN_2_IN) ++#define GPIO29_SCLK_MD (29 | GPIO_ALT_FN_3_IN) + #define GPIO30_SDATA_OUT_AC97_MD (30 | GPIO_ALT_FN_2_OUT) + #define GPIO30_SDATA_OUT_I2S_MD (30 | GPIO_ALT_FN_1_OUT) ++#define GPIO30_USB_P3_2 (30 | GPIO_ALT_FN_3_OUT) + #define GPIO31_SYNC_I2S_MD (31 | GPIO_ALT_FN_1_OUT) + #define GPIO31_SYNC_AC97_MD (31 | GPIO_ALT_FN_2_OUT) ++#define GPIO31_USB_P3_6 (31 | GPIO_ALT_FN_3_OUT) + #define GPIO32_SDATA_IN1_AC97_MD (32 | GPIO_ALT_FN_1_IN) + #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 GPIO34_FFRXD_MD (34 | GPIO_ALT_FN_1_IN) + #define GPIO34_MMCCS0_MD (34 | GPIO_ALT_FN_2_OUT) ++#define GPIO34_USB_P2_2_MD (34 | GPIO_ALT_FN_1_OUT) + #define GPIO35_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) ++#define GPIO35_USB_P2_1_MD (35 | GPIO_ALT_FN_2_IN) + #define GPIO36_FFDCD_MD (36 | GPIO_ALT_FN_1_IN) ++#define GPIO36_USB_P2_4_MD (36 | GPIO_ALT_FN_1_OUT) + #define GPIO37_FFDSR_MD (37 | GPIO_ALT_FN_1_IN) ++#define GPIO37_SFRM2_MD (37 | GPIO_ALT_FN_2_IN) + #define GPIO38_FFRI_MD (38 | GPIO_ALT_FN_1_IN) ++#define GPIO38_STXD2_MD (38 | GPIO_ALT_FN_2_OUT) + #define GPIO39_MMCCS1_MD (39 | GPIO_ALT_FN_1_OUT) + #define GPIO39_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) ++#define GPIO39_USB_P2_6_MD (39 | GPIO_ALT_FN_1_OUT) + #define GPIO40_FFDTR_MD (40 | GPIO_ALT_FN_2_OUT) ++#define GPIO40_USB_P2_5_MD (40 | GPIO_ALT_FN_3_IN) + #define GPIO41_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) + #define GPIO42_BTRXD_MD (42 | GPIO_ALT_FN_1_IN) + #define GPIO42_HWRXD_MD (42 | GPIO_ALT_FN_3_IN) +@@ -1421,13 +1435,17 @@ + #define GPIO51_HWRTS_MD (51 | GPIO_ALT_FN_1_OUT) + #define GPIO51_nPIOW_MD (51 | GPIO_ALT_FN_2_OUT) + #define GPIO52_nPCE_1_MD (52 | GPIO_ALT_FN_2_OUT) ++#define GPIO52_SCLK3_MD (52 | GPIO_ALT_FN_2_OUT) + #define GPIO53_nPCE_2_MD (53 | GPIO_ALT_FN_2_OUT) + #define GPIO53_MMCCLK_MD (53 | GPIO_ALT_FN_1_OUT) ++#define GPIO53_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) ++#define GPIO53_USB_P2_3_MD (53 | GPIO_ALT_FN_2_IN) + #define GPIO54_MMCCLK_MD (54 | GPIO_ALT_FN_1_OUT) + #define GPIO54_nPCE_2_MD (54 | GPIO_ALT_FN_2_OUT) + #define GPIO54_pSKTSEL_MD (54 | GPIO_ALT_FN_2_OUT) + #define GPIO55_nPREG_MD (55 | GPIO_ALT_FN_2_OUT) + #define GPIO56_nPWAIT_MD (56 | GPIO_ALT_FN_1_IN) ++#define GPIO56_USB_P3_4 (56 | GPIO_ALT_FN_1_OUT) + #define GPIO57_nIOIS16_MD (57 | GPIO_ALT_FN_1_IN) + #define GPIO58_LDD_0_MD (58 | GPIO_ALT_FN_2_OUT) + #define GPIO59_LDD_1_MD (59 | GPIO_ALT_FN_2_OUT) +@@ -1463,13 +1481,19 @@ + #define GPIO80_nCS_4_MD (80 | GPIO_ALT_FN_2_OUT) + #define GPIO81_NSSP_CLK_OUT (81 | GPIO_ALT_FN_1_OUT) + #define GPIO81_NSSP_CLK_IN (81 | GPIO_ALT_FN_1_IN) ++#define GPIO81_STXD3_MD (81 | GPIO_ALT_FN_1_OUT) + #define GPIO82_NSSP_FRM_OUT (82 | GPIO_ALT_FN_1_OUT) + #define GPIO82_NSSP_FRM_IN (82 | GPIO_ALT_FN_1_IN) + #define GPIO83_NSSP_TX (83 | GPIO_ALT_FN_1_OUT) + #define GPIO83_NSSP_RX (83 | GPIO_ALT_FN_2_IN) ++#define GPIO83_SFRM3_MD (83 | GPIO_ALT_FN_1_IN) + #define GPIO84_NSSP_TX (84 | GPIO_ALT_FN_1_OUT) + #define GPIO84_NSSP_RX (84 | GPIO_ALT_FN_2_IN) + #define GPIO85_nPCE_1_MD (85 | GPIO_ALT_FN_1_OUT) ++#define GPIO88_SRXD2_MD (88 | GPIO_ALT_FN_2_IN) ++#define GPIO89_SRXD3_MD (89 | GPIO_ALT_FN_1_IN) ++#define GPIO90_USB_P3_5 (90 | GPIO_ALT_FN_2_IN) ++#define GPIO91_USB_P3_1 (91 | GPIO_ALT_FN_2_IN) + #define GPIO92_MMCDAT0_MD (92 | GPIO_ALT_FN_1_OUT) + #define GPIO102_nPCE_1_MD (102 | GPIO_ALT_FN_1_OUT) + #define GPIO104_pSKTSEL_MD (104 | GPIO_ALT_FN_1_OUT) +@@ -1481,6 +1505,7 @@ + #define GPIO112_MMCCMD_MD (112 | GPIO_ALT_FN_1_OUT) + #define GPIO113_I2S_SYSCLK_MD (113 | GPIO_ALT_FN_1_OUT) + #define GPIO113_AC97_RESET_N_MD (113 | GPIO_ALT_FN_2_OUT) ++#define GPIO113_USB_P3_3 (113 | GPIO_ALT_FN_3_IN) + #define GPIO117_I2CSCL_MD (117 | GPIO_ALT_FN_1_OUT) + #define GPIO118_I2CSDA_MD (118 | GPIO_ALT_FN_1_IN) + +@@ -1496,6 +1521,7 @@ + #define PFER __REG(0x40F00014) /* Power Manager GPIO Falling-Edge Detect Enable Register */ + #define PEDR __REG(0x40F00018) /* Power Manager GPIO Edge Detect Status Register */ + #define PCFR __REG(0x40F0001C) /* Power Manager General Configuration Register */ ++#define PGSR(x) (__REG(0x40F00020 + ((unsigned long)(x)/32*4))) + #define PGSR0 __REG(0x40F00020) /* Power Manager GPIO Sleep State Register for GP[31-0] */ + #define PGSR1 __REG(0x40F00024) /* Power Manager GPIO Sleep State Register for GP[63-32] */ + #define PGSR2 __REG(0x40F00028) /* Power Manager GPIO Sleep State Register for GP[84-64] */ +Index: linux-2.6.20.7/arch/arm/boot/compressed/head.S +=================================================================== +--- linux-2.6.20.7.orig/arch/arm/boot/compressed/head.S 2007-04-21 22:31:54.000000000 -0300 ++++ linux-2.6.20.7/arch/arm/boot/compressed/head.S 2007-04-21 22:32:53.000000000 -0300 +@@ -117,6 +117,9 @@ + mov r0, r0 + .endr + ++ mov r1, #0x300 @ mach_id 0x363 is official EZX ++ orr r1, r1, #0x63 @ bootloader JUMP doesn't set r1 ++ + b 1f + .word 0x016f2818 @ Magic numbers to help the loader + .word start @ absolute load/run zImage address +Index: linux-2.6.20.7/include/asm-arm/arch-pxa/uncompress.h +=================================================================== +--- linux-2.6.20.7.orig/include/asm-arm/arch-pxa/uncompress.h 2007-04-21 22:31:54.000000000 -0300 ++++ linux-2.6.20.7/include/asm-arm/arch-pxa/uncompress.h 2007-04-21 22:32:53.000000000 -0300 +@@ -14,14 +14,14 @@ + #define STUART ((volatile unsigned long *)0x40700000) + #define HWUART ((volatile unsigned long *)0x41600000) + +-#define UART FFUART ++#define UART STUART + + + static inline void putc(char c) + { +- while (!(UART[5] & 0x20)) ++/* while (!(UART[5] & 0x40)) + barrier(); +- UART[0] = c; ++ UART[0] = c;*/ + } + + /* +Index: linux-2.6.20.7/arch/arm/mach-pxa/ezx_ssp.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/arch/arm/mach-pxa/ezx_ssp.c 2007-04-22 01:36:48.000000000 -0300 +@@ -0,0 +1,130 @@ ++/* ++ * SSP control code for Motorola EZX phones ++ * ++ * Copyright (c) 2007 Daniel Ribeiro <drwyrm@gmail.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/delay.h> ++#include <linux/platform_device.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++ ++#include <asm/arch/ssp.h> ++#include <asm/arch/pxa-regs.h> ++ ++#include "ezx.h" ++ ++static DEFINE_SPINLOCK(ezx_ssp_lock); ++static struct ssp_dev ezx_ssp_dev; ++static struct ssp_state ezx_ssp_state; ++static struct ezxssp_machinfo *ssp_machinfo; ++ ++/* PCAP */ ++unsigned long ezx_ssp_pcap_putget(ulong data) ++{ ++ unsigned long flag; ++ u32 ret = 0; ++ ++ spin_lock_irqsave(&ezx_ssp_lock, flag); ++ if (ssp_machinfo->cs_pcap >= 0) ++ GPCR(ssp_machinfo->cs_pcap) = GPIO_bit(ssp_machinfo->cs_pcap); ++ ++ ssp_write_word(&ezx_ssp_dev,data); ++ ssp_read_word(&ezx_ssp_dev, &ret); ++ ++ if (ssp_machinfo->cs_pcap >= 0) ++ GPSR(ssp_machinfo->cs_pcap) = GPIO_bit(ssp_machinfo->cs_pcap); ++ spin_unlock_irqrestore(&ezx_ssp_lock, flag); ++ ++ return ret; ++} ++EXPORT_SYMBOL(ezx_ssp_pcap_putget); ++ ++/* ASSP */ ++ ++/* NSSP */ ++ ++void __init ezx_ssp_set_machinfo(struct ezxssp_machinfo *machinfo) ++{ ++ ssp_machinfo = machinfo; ++} ++ ++static int __init ezx_ssp_probe(struct platform_device *dev) ++{ ++ int ret; ++ /* PCAP init */ ++ pxa_gpio_mode(29|GPIO_ALT_FN_3_OUT); ++ pxa_gpio_mode(GPIO24_SFRM_MD); ++ pxa_gpio_mode(GPIO25_STXD_MD); ++ pxa_gpio_mode(GPIO26_SRXD_MD); ++ ++ /* Chip Select - Disable All */ ++ if (ssp_machinfo->cs_pcap >= 0) ++ pxa_gpio_mode(ssp_machinfo->cs_pcap | GPIO_OUT | GPIO_DFLT_HIGH); ++ ++ ret = ssp_init(&ezx_ssp_dev, ssp_machinfo->port, 0); ++ ++ if (ret) ++ printk(KERN_ERR "Unable to register SSP handler!\n"); ++ else { ++ ssp_disable(&ezx_ssp_dev); ++ ssp_config(&ezx_ssp_dev, ++ (SSCR0_Motorola | SSCR0_DataSize(16) | SSCR0_EDSS), ++ (SSCR1_TxTresh(1) | SSCR1_RxTresh(1)), ++ 0, SSCR0_SerClkDiv(ssp_machinfo->clk_pcap)); ++ ssp_enable(&ezx_ssp_dev); ++ } ++ ++ return ret; ++} ++ ++static int ezx_ssp_remove(struct platform_device *dev) ++{ ++ ssp_exit(&ezx_ssp_dev); ++ return 0; ++} ++ ++static int ezx_ssp_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ ssp_flush(&ezx_ssp_dev); ++ ssp_save_state(&ezx_ssp_dev,&ezx_ssp_state); ++ ++ return 0; ++} ++ ++static int ezx_ssp_resume(struct platform_device *dev) ++{ ++ if (ssp_machinfo->cs_pcap >= 0) ++ GPSR(ssp_machinfo->cs_pcap) = GPIO_bit(ssp_machinfo->cs_pcap); ++ ssp_restore_state(&ezx_ssp_dev,&ezx_ssp_state); ++ ssp_enable(&ezx_ssp_dev); ++ ++ return 0; ++} ++ ++static struct platform_driver ezxssp_driver = { ++ .probe = ezx_ssp_probe, ++ .remove = ezx_ssp_remove, ++ .suspend = ezx_ssp_suspend, ++ .resume = ezx_ssp_resume, ++ .driver = { ++ .name = "ezx-ssp", ++ }, ++}; ++ ++int __init ezx_ssp_init(void) ++{ ++ return platform_driver_register(&ezxssp_driver); ++} ++ ++arch_initcall(ezx_ssp_init); +Index: linux-2.6.20.7/arch/arm/mach-pxa/ezx.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/arch/arm/mach-pxa/ezx.h 2007-04-22 01:38:55.000000000 -0300 +@@ -0,0 +1,9 @@ ++#include <asm/arch/ezx.h> ++ ++/* SSP */ ++struct ezxssp_machinfo { ++ int port; ++ int cs_pcap; ++ int clk_pcap; ++}; ++ +Index: linux-2.6.20.7/arch/arm/mach-pxa/ezx_lcd.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/arch/arm/mach-pxa/ezx_lcd.c 2007-04-21 22:32:53.000000000 -0300 +@@ -0,0 +1,112 @@ ++/* ++ * linux/arch/arm/mach-ezx/a780.c ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Zhuang Xiaofan ++ * Created: Nov 25, 2003 ++ * Copyright: Motorola Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/fb.h> ++#include <linux/delay.h> ++#include <asm/arch/pxafb.h> ++#include <asm/arch/pxa-regs.h> ++ ++/* ++ * EZX PXA Framebuffer ++ */ ++ ++static void pxafb_lcd_power(int on, struct fb_var_screeninfo *var) ++{ ++ if (on) { ++// mdelay(1); ++ GPSR3 = 0x00100000; ++ mdelay(10); ++ GPCR3 = 0x00100000; ++ GPDR3 |= 0x00100000; ++ } else { ++ GPSR3 = 0x00100000; ++ PGSR3 |= 0x00100000; ++ mdelay(41); ++ LCCR0 &= ~LCCR0_LDM; /* disable lcd disable done interrupt */ ++ LCCR0 |= LCCR0_DIS; /* normal disable lcd */ ++ mdelay(18); ++ } ++} ++ ++#ifdef CONFIG_PXA_E2 ++static void sumatra_backlight_power(int on) ++{ ++ if (on) { ++ pxa_gpio_mode(GPIO16_PWM0_MD); ++ pxa_set_cken(CKEN0_PWM0, 1); ++ PWM_CTRL0 = 0; ++ PWM_PWDUTY0 = 0x3ff; ++ PWM_PERVAL0 = 0x3ff; ++ } else { ++ PWM_CTRL0 = 0; ++ PWM_PWDUTY0 = 0x0; ++ PWM_PERVAL0 = 0x3FF; ++ pxa_set_cken(CKEN0_PWM0, 0); ++ } ++} ++ ++static struct pxafb_mode_info mode_ezx = { ++ .pixclock = 192308, ++ .xres = 240, ++ .yres = 320, ++ .bpp = 8, ++ .hsync_len = 10, ++ .left_margin = 20, ++ .right_margin = 10, ++ .vsync_len = 2, ++ .upper_margin = 3, ++ .lower_margin = 2, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++}; ++ ++static struct pxafb_mach_info ezx_fb_info __initdata = { ++ .modes = &mode_ezx, ++ .num_modes = 1, ++ .lccr0 = 0x022008B8, ++ .lccr3 = 0xC130FF13, ++ .pxafb_backlight_power = sumatra_backlight_power, ++ .pxafb_lcd_power = &pxafb_lcd_power, ++}; ++ ++#else ++static struct pxafb_mode_info mode_ezx = { ++ .pixclock = 150000, ++ .xres = 240, ++ .yres = 320, ++ .bpp = 16, ++ .hsync_len = 10, ++ .left_margin = 20, ++ .right_margin = 10, ++ .vsync_len = 2, ++ .upper_margin = 3, ++ .lower_margin = 2, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++}; ++ ++static struct pxafb_mach_info ezx_fb_info __initdata = { ++ .modes = &mode_ezx, ++ .num_modes = 1, ++ .lccr0 = 0x002008F8, ++ .lccr3 = 0x0430FF09, ++ .pxafb_lcd_power= &pxafb_lcd_power, ++}; ++#endif ++ ++int __init __ezx_lcd_init (void) ++{ ++ set_pxa_fb_info(&ezx_fb_info); ++ return 0; ++} ++ ++arch_initcall(__ezx_lcd_init); +Index: linux-2.6.20.7/arch/arm/mm/init.c +=================================================================== +--- linux-2.6.20.7.orig/arch/arm/mm/init.c 2007-04-21 22:32:57.000000000 -0300 ++++ linux-2.6.20.7/arch/arm/mm/init.c 2007-04-21 22:44:03.000000000 -0300 +@@ -241,6 +241,10 @@ + */ + reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT, + boot_pages << PAGE_SHIFT); ++#ifdef CONFIG_ARCH_EZX ++ /* reserve the first page memory for exiting sleep and user off */ ++ reserve_bootmem_node(pgdat, PHYS_OFFSET, PAGE_SIZE); ++#endif + + #ifdef CONFIG_BLK_DEV_INITRD + /* diff --git a/packages/linux/linux-ezx-2.6.20.7/ezx-emu.patch b/packages/linux/linux-ezx-2.6.20.7/ezx-emu.patch new file mode 100644 index 0000000000..de9de60461 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/ezx-emu.patch @@ -0,0 +1,332 @@ +Index: linux-2.6.20.7/arch/arm/mach-pxa/ezx-emu.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/arch/arm/mach-pxa/ezx-emu.c 2007-04-21 12:33:22.000000000 -0300 +@@ -0,0 +1,215 @@ ++/* ++ * EMU Driver for Motorola EZX phones ++ * ++ * Copyright (c) 2007 Daniel Ribeiro <drwyrm@gmail.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/interrupt.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++ ++#include <asm/arch/hardware.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/ezx.h> ++#include <asm/arch/ezx-pcap.h> ++#include <asm/arch/udc.h> ++ ++static struct pxa2xx_udc_mach_info ezx_udc_info; ++extern int ezx_pcap_bit_set(u_int32_t, u_int8_t); ++extern int ezx_pcap_read_bit(u_int32_t); ++ ++void emu_switch_to_usb(void) ++{ ++ pxa_gpio_mode(GPIO34_USB_P2_2_MD); ++ pxa_gpio_mode(GPIO35_USB_P2_1_MD); ++ pxa_gpio_mode(GPIO36_USB_P2_4_MD); ++ pxa_gpio_mode(GPIO39_USB_P2_6_MD); ++ pxa_gpio_mode(GPIO40_USB_P2_5_MD); ++ pxa_gpio_mode(GPIO53_USB_P2_3_MD); ++ UP2OCR = 0x02000000; ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_FSENB, 0); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN, 1); ++ clr_GPIO(GPIO_EMU_MUX1); ++ clr_GPIO(GPIO_EMU_MUX2); ++} ++EXPORT_SYMBOL(emu_switch_to_usb); ++ ++void emu_switch_to_uart(void) ++{ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN,0); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB, 0); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232_DIR, 1); ++ set_GPIO(GPIO39_FFTXD); ++ pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); ++ set_GPIO(GPIO34_TXENB); ++ pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); ++ pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); ++ pxa_gpio_mode(GPIO39_FFTXD_MD); ++ pxa_gpio_mode(GPIO53_FFRXD_MD); ++ CKEN |= CKEN6_FFUART; ++ clr_GPIO(GPIO_EMU_MUX1); ++ clr_GPIO(GPIO_EMU_MUX2); ++ ++} ++EXPORT_SYMBOL(emu_switch_to_uart); ++ ++void emu_switch_to_audio(int stereo) ++{ ++ clr_GPIO(GPIO39_VPOUT); ++ if (stereo) { ++ pxa_gpio_mode(GPIO34_USB_P2_2 | GPIO_IN); ++ clr_GPIO(GPIO39_VPOUT); ++ } else { ++ pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); ++ set_GPIO(GPIO34_TXENB); ++ } ++ ++ pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); ++ pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); ++ pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); ++ set_GPIO(GPIO_EMU_MUX1); ++ if (stereo) ++ set_GPIO(GPIO_EMU_MUX2); ++ else ++ clr_GPIO(GPIO_EMU_MUX2); ++} ++ ++void emu_switch_to_nothing(void) ++{ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN, 0); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB, 1); ++ pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); ++ set_GPIO(GPIO34_TXENB); ++ pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); ++ pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); ++ pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); ++} ++ ++ ++static irqreturn_t emu_irq(int irq, void *data) ++{ ++ printk("emu_irq(%u) entered: ", irq); ++ ++ switch (irq) { ++ case EZX_IRQ_USB4V: ++ printk("usb 4v\n"); ++ if(ezx_pcap_read_bit(SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V)) ++#if defined CONFIG_PXA_EZX_EMU_USB ++ emu_switch_to_usb(); ++#elif defined CONFIG_PXA_EZX_EMU_UART ++ emu_switch_to_uart(); ++#else ++ emu_switch_to_nothing(); ++#endif ++ else ++ emu_switch_to_nothing(); ++ break; ++ case EZX_IRQ_USB1V: ++ printk("usb 1v\n"); ++ break; ++ default: ++ printk("unknown\n"); ++ break; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int __init ezx_emu_probe(struct platform_device *dev) ++{ ++ printk("ezx_emu_probe entered!\n"); ++ pxa_gpio_mode(GPIO_SNP_INT_IN | GPIO_IN); ++ pxa_gpio_mode(GPIO_EMU_MUX1 | GPIO_OUT); ++ pxa_gpio_mode(GPIO_EMU_MUX2 | GPIO_OUT); ++ ++ request_irq(EZX_IRQ_USB4V, &emu_irq, SA_INTERRUPT, "usb 4v", NULL); ++ request_irq(EZX_IRQ_USB1V, &emu_irq, SA_INTERRUPT, "usb 1v", NULL); ++ ++ pxa_set_udc_info(&ezx_udc_info); ++ ++#if defined CONFIG_PXA_EZX_EMU_USB ++ emu_switch_to_usb(); ++#elif defined CONFIG_PXA_EZX_EMU_UART ++ emu_switch_to_uart(); ++#else ++ emu_switch_to_nothing(); ++#endif ++ ++ return 0; ++} ++ ++static int ezx_emu_remove(struct platform_device *dev) ++{ ++ free_irq(EZX_IRQ_USB4V, NULL); ++ free_irq(EZX_IRQ_USB1V, NULL); ++ ++ return 0; ++} ++ ++/* USB Device Controller */ ++static int udc_connected_status; ++static void ezx_udc_command(int cmd) ++{ ++ switch (cmd) { ++ case PXA2XX_UDC_CMD_DISCONNECT: ++ printk(KERN_NOTICE "USB cmd disconnect\n"); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU,0); ++ udc_connected_status = 0; ++ break; ++ case PXA2XX_UDC_CMD_CONNECT: ++ printk(KERN_NOTICE "USB cmd connect\n"); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU,1); ++ udc_connected_status = 1; ++ break; ++ } ++} ++ ++static int ezx_udc_is_connected(void) ++{ ++ return udc_connected_status; ++} ++ ++static struct pxa2xx_udc_mach_info ezx_udc_info __initdata = { ++ .udc_is_connected = ezx_udc_is_connected, ++ .udc_command = ezx_udc_command, ++}; ++ ++static struct platform_driver ezxemu_driver = { ++ .probe = ezx_emu_probe, ++ .remove = ezx_emu_remove, ++ //.suspend = ezx_emu_suspend, ++ //.resume = ezx_emu_resume, ++ .driver = { ++ .name = "ezx-emu", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init ezx_emu_init(void) ++{ ++ return platform_driver_register(&ezxemu_driver); ++} ++ ++void ezx_emu_fini(void) ++{ ++ return platform_driver_unregister(&ezxemu_driver); ++} ++ ++module_init(ezx_emu_init); ++module_exit(ezx_emu_fini); ++ ++MODULE_DESCRIPTION("Motorola Enchanced Mini Usb driver"); ++MODULE_AUTHOR("Daniel Ribeiro <drwyrm@gmail.com>"); ++MODULE_LICENSE("GPL"); +Index: linux-2.6.20.7/arch/arm/mach-pxa/Kconfig +=================================================================== +--- linux-2.6.20.7.orig/arch/arm/mach-pxa/Kconfig 2007-04-21 12:32:50.000000000 -0300 ++++ linux-2.6.20.7/arch/arm/mach-pxa/Kconfig 2007-04-21 12:32:54.000000000 -0300 +@@ -94,6 +94,27 @@ + + endchoice + ++config PXA_EZX_EMU ++ bool "Motorola Enchanced Mini Usb" ++ ++if PXA_EZX_EMU ++ ++choice ++ prompt "Select default EMU mode" ++ ++config PXA_EZX_EMU_USB ++ bool "USB" ++ ++config PXA_EZX_EMU_UART ++ bool "UART" ++ ++config PXA_EZX_EMU_NOTHING ++ bool "nothing" ++ ++endchoice ++ ++endif ++ + endif + + endmenu +Index: linux-2.6.20.7/arch/arm/mach-pxa/Makefile +=================================================================== +--- linux-2.6.20.7.orig/arch/arm/mach-pxa/Makefile 2007-04-21 12:32:50.000000000 -0300 ++++ linux-2.6.20.7/arch/arm/mach-pxa/Makefile 2007-04-21 12:32:54.000000000 -0300 +@@ -19,6 +19,7 @@ + obj-$(CONFIG_MACH_POODLE) += poodle.o corgi_ssp.o + obj-$(CONFIG_MACH_TOSA) += tosa.o + obj-$(CONFIG_PXA_EZX) += ezx.o ezx_lcd.o ezx_ssp.o ezx-pcap.o ezx-mci.o ++obj-$(CONFIG_PXA_EZX_EMU) += ezx-emu.o + + # Support for blinky lights + led-y := leds.o +Index: linux-2.6.20.7/arch/arm/mach-pxa/ezx.c +=================================================================== +--- linux-2.6.20.7.orig/arch/arm/mach-pxa/ezx.c 2007-04-21 12:32:50.000000000 -0300 ++++ linux-2.6.20.7/arch/arm/mach-pxa/ezx.c 2007-04-21 12:32:54.000000000 -0300 +@@ -36,6 +36,7 @@ + #include <asm/arch/ohci.h> + #include <asm/arch/pxa-regs.h> + ++ + #include "ezx.h" + #include "generic.h" + #include <linux/tty.h> +@@ -92,6 +93,30 @@ + .resource = ezxpcap_resources, + }; + ++/* EMU */ ++static struct resource ezxemu_resources[] = { ++ [0] = { ++ .start = EZX_IRQ_USB4V, ++ .end = EZX_IRQ_USB4V, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [1] = { ++ .start = EZX_IRQ_USB1V, ++ .end = EZX_IRQ_USB1V, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++struct platform_device ezxemu_device = { ++ .name = "ezx-emu", ++ .id = -1, ++// .dev = { ++// .parent = &ezxpcap_device.dev, ++// }, ++ .num_resources = ARRAY_SIZE(ezxemu_resources), ++ .resource = ezxemu_resources, ++}; ++ + /* OHCI Controller */ + + static int ezx_ohci_init(struct device *dev) +@@ -317,6 +342,7 @@ + &ezxssp_device, + &ezxpcap_device, + &ezxbp_device, ++ &ezxemu_device, + }; + + static void __init a780_init(void) +@@ -383,7 +409,15 @@ + pxa_set_ohci_info(&ezx_ohci_platform_data); + + platform_add_devices(devices, ARRAY_SIZE(devices)); +- ++/* ++#if defined CONFIG_PXA_EZX_EMU_USB ++ emu_switch_to_usb(); ++#elif defined CONFIG_PXA_EZX_EMU_UART ++ emu_switch_to_uart(); ++#else ++ emu_switch_to_nothing(); ++#endif ++*/ + } + + MACHINE_START(EZX, "Motorola Ezx Platform") diff --git a/packages/linux/linux-ezx-2.6.20.7/ezx-fix-usb_pxa27x_udc-r3.patch b/packages/linux/linux-ezx-2.6.20.7/ezx-fix-usb_pxa27x_udc-r3.patch new file mode 100644 index 0000000000..c3cbf25a09 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/ezx-fix-usb_pxa27x_udc-r3.patch @@ -0,0 +1,16 @@ +Index: linux-2.6.20.7/drivers/usb/gadget/pxa27x_udc.c +=================================================================== +--- linux-2.6.20.7.orig/drivers/usb/gadget/pxa27x_udc.c 2007-04-21 12:30:51.000000000 -0300 ++++ linux-2.6.20.7/drivers/usb/gadget/pxa27x_udc.c 2007-04-21 12:32:21.000000000 -0300 +@@ -1615,8 +1615,9 @@ + + DMSG("Connecting\n"); + /* RPFIXME */ +- UP2OCR = UP2OCR_HXOE | UP2OCR_DPPUE | UP2OCR_DPPUBE; +- //dev->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); ++ //UP2OCR = UP2OCR_HXOE | UP2OCR_DPPUE | UP2OCR_DPPUBE; ++ UP2OCR = 0x02000000; // temporary solution for ezx. ++ dev->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); + } + + diff --git a/packages/linux/linux-ezx-2.6.20.7/ezx-mci.patch b/packages/linux/linux-ezx-2.6.20.7/ezx-mci.patch new file mode 100644 index 0000000000..d16693e3e4 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/ezx-mci.patch @@ -0,0 +1,177 @@ +Index: linux-2.6.20.7/arch/arm/mach-pxa/ezx-mci.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/arch/arm/mach-pxa/ezx-mci.c 2007-04-20 01:10:13.000000000 -0300 +@@ -0,0 +1,159 @@ ++/* ++ * linux/arch/arm/mach-ezx/a780.c ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Zhuang Xiaofan ++ * Created: Nov 25, 2003 ++ * Copyright: Motorola Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/mmc/host.h> ++#include <linux/irq.h> ++#include <asm/irq.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/ezx-pcap.h> ++#include <asm/arch/mmc.h> ++#include <asm/arch/hardware.h> ++ ++extern int ezx_pcap_mmcsd_power(int); ++extern void ezx_pcap_mmcsd_voltage(u_int32_t); ++ ++static struct pxamci_platform_data ezx_mci_platform_data; ++ ++static int ezx_mci_init(struct device *dev, ++ irqreturn_t (*ezx_detect_int)(int, void *), ++ void *data) ++{ ++ int err; ++ printk("%s entered\n", __FUNCTION__); ++ ++ /* Setup GPIO for PXA27x MMC/SD 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); ++ ++ ezx_pcap_mmcsd_power(1); ++ ++ ezx_mci_platform_data.detect_delay = msecs_to_jiffies(250); ++ ++ err = request_irq(0x49, ezx_detect_int, SA_INTERRUPT, ++ "MMC card detect", data); ++ if (err) { ++ printk(KERN_ERR "ezx_mci_detect: MMC/SD: can't request " ++ "MMC card detect IRQ\n"); ++ return -1; ++ } ++ ++ set_irq_type(0x0b, IRQT_BOTHEDGE); ++ ++ return 0; ++} ++ ++static int ezx_mci_get_ro(struct device *dev) ++{ ++ printk("%s entered\n", __FUNCTION__); ++#if defined(CONFIG_PXA_EZX_E680) ++ /* this is only e680, i guess */ ++ // return GPIO_is_high(96+4); ++ return (GPLR3 & 0x800); ++#else ++ return 0; ++#endif ++} ++ ++#if defined(CONFIG_PXA_EZX_A780) ++static u_int8_t mmc_voltage[] = { ++ [MMC_VDD_160] = 5, ++ [MMC_VDD_170] = 5, ++ [MMC_VDD_180] = 6, ++ [MMC_VDD_190] = 6, ++ [MMC_VDD_200] = 7, ++ [MMC_VDD_210] = 7, ++ [MMC_VDD_220] = 8, ++ [MMC_VDD_230] = 8, ++ [MMC_VDD_240] = 9, ++ [MMC_VDD_250] = 9, ++ [MMC_VDD_260] = 10, ++ [MMC_VDD_270] = 10, ++ [MMC_VDD_280] = 11, ++ [MMC_VDD_290] = 11, ++ [MMC_VDD_300] = 12, ++ [MMC_VDD_310] = 12, ++ [MMC_VDD_320] = 13, ++ [MMC_VDD_330] = 13, ++ [MMC_VDD_340] = 14, ++ [MMC_VDD_350] = 14, ++ [MMC_VDD_360] = 15, ++}; ++#elif defined(CONFIG_PXA_EZX_E680) ++static u_int8_t mmc_voltage[] = { ++ [MMC_VDD_160] = 3, ++ [MMC_VDD_170] = 3, ++ [MMC_VDD_180] = 3, ++ [MMC_VDD_190] = 3, ++ [MMC_VDD_200] = 3, ++ [MMC_VDD_210] = 3, ++ [MMC_VDD_220] = 3, ++ [MMC_VDD_230] = 3, ++ [MMC_VDD_240] = 3, ++ [MMC_VDD_250] = 3, ++ [MMC_VDD_260] = 3, ++ [MMC_VDD_270] = 3, ++ [MMC_VDD_280] = 3, ++ [MMC_VDD_290] = 3, ++ [MMC_VDD_300] = 3, ++ [MMC_VDD_310] = 3, ++ [MMC_VDD_320] = 3, ++ [MMC_VDD_330] = 3, ++ [MMC_VDD_340] = 3, ++ [MMC_VDD_350] = 3, ++ [MMC_VDD_360] = 3, ++}; ++#endif ++ ++static void ezx_mci_setpower(struct device *dev, unsigned int vdd) ++{ ++ printk("%s(vdd=%u) entered\n", __FUNCTION__, vdd); ++ if (vdd <= MMC_VDD_360) ++ ezx_pcap_mmcsd_voltage(mmc_voltage[vdd]); ++ ++ ezx_pcap_mmcsd_power(1); ++} ++ ++static void ezx_mci_exit(struct device *dev, void *data) ++{ ++ printk("%s entered\n", __FUNCTION__); ++ ezx_pcap_mmcsd_power(0); ++ free_irq(0x49, data); ++} ++ ++static struct pxamci_platform_data ezx_mci_platform_data = { ++#if defined(CONFIG_PXA_EZX_E680) ++ .ocr_mask = MMC_VDD_27_28, ++#elif defined(CONFIG_PXA_EZX_A780) ++ .ocr_mask = MMC_VDD_160_165|MMC_VDD_18_19|MMC_VDD_20_21 ++ |MMC_VDD_22_23|MMC_VDD_24_25|MMC_VDD_26_27 ++ |MMC_VDD_28_29|MMC_VDD_30_31|MMC_VDD_32_33 ++ |MMC_VDD_34_35|MMC_VDD_35_36, ++#endif ++ .init = ezx_mci_init, ++ .get_ro = ezx_mci_get_ro, ++ .setpower = ezx_mci_setpower, ++ .exit = ezx_mci_exit, ++}; ++ ++int __init __ezx_mci_init (void) ++{ ++ pxa_set_mci_info(&ezx_mci_platform_data); ++ return 0; ++} ++ ++arch_initcall(__ezx_mci_init); +Index: linux-2.6.20.7/arch/arm/mach-pxa/Makefile +=================================================================== +--- linux-2.6.20.7.orig/arch/arm/mach-pxa/Makefile 2007-04-21 02:56:16.000000000 -0300 ++++ linux-2.6.20.7/arch/arm/mach-pxa/Makefile 2007-04-21 03:00:03.000000000 -0300 +@@ -18,7 +18,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_PXA_EZX) += ezx.o ezx_lcd.o ezx_ssp.o ezx-pcap.o ++obj-$(CONFIG_PXA_EZX) += ezx.o ezx_lcd.o ezx_ssp.o ezx-pcap.o ezx-mci.o + + # Support for blinky lights + led-y := leds.o diff --git a/packages/linux/linux-ezx-2.6.20.7/ezx-mtd-map.patch b/packages/linux/linux-ezx-2.6.20.7/ezx-mtd-map.patch new file mode 100644 index 0000000000..f59e31d9a2 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/ezx-mtd-map.patch @@ -0,0 +1,274 @@ +Index: linux-2.6.20.7/drivers/mtd/maps/Kconfig +=================================================================== +--- linux-2.6.20.7.orig/drivers/mtd/maps/Kconfig 2007-04-21 12:47:04.000000000 -0300 ++++ linux-2.6.20.7/drivers/mtd/maps/Kconfig 2007-04-21 13:01:08.000000000 -0300 +@@ -595,6 +595,28 @@ + help + This enables access to the flash chip on the Sharp SL Series of PDAs. + ++config MTD_EZX ++ bool "Map driver for Motorola EZX Platform" ++ depends on MTD && PXA_EZX ++ ++if MTD_EZX ++ ++choice ++ prompt "Select partition mapping for EZX platform" ++ ++config MTD_EZX_A780 ++ bool "A780/E680 Original Mapping" ++ ++config MTD_EZX_A780_ALTERNATE ++ bool "A780/E680 Alternate Mapping for BLOB2" ++ ++config MTD_EZX_E2 ++ bool "E2 Original Mapping" ++ ++endchoice ++ ++endif ++ + config MTD_PLATRAM + tristate "Map driver for platform device RAM (mtd-ram)" + depends on MTD +Index: linux-2.6.20.7/drivers/mtd/maps/Makefile +=================================================================== +--- linux-2.6.20.7.orig/drivers/mtd/maps/Makefile 2007-04-21 12:55:09.000000000 -0300 ++++ linux-2.6.20.7/drivers/mtd/maps/Makefile 2007-04-21 12:55:45.000000000 -0300 +@@ -72,3 +72,4 @@ + obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o + obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o + obj-$(CONFIG_MTD_TQM834x) += tqm834x.o ++obj-$(CONFIG_MTD_EZX) += ezx-flash.o +Index: linux-2.6.20.7/drivers/mtd/maps/ezx-flash.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/drivers/mtd/maps/ezx-flash.c 2007-04-21 13:07:14.000000000 -0300 +@@ -0,0 +1,227 @@ ++/* ++ * $Id: $ ++ * ++ * Map driver for the PXA27x ++ * ++ * Author: Harald Welte ++ * Copyright: (C) 2001 MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Mar 3, 2007 - (Daniel Ribeiro) Alternate partition table ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/dma-mapping.h> ++#include <linux/slab.h> ++ ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++ ++#include <asm/io.h> ++#include <asm/hardware.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/mainstone.h> ++ ++#define WINDOW_ADDR 0x0 ++#define WINDOW_SIZE (32*1024*1024) ++#define WINDOW_CACHE_ADDR 0x0 ++#define WINDOW_CACHE_SIZE 0x1a00000 ++ ++static void pxa27x_map_inval_cache(struct map_info *map, unsigned long from, ++ ssize_t len) ++{ ++#if 0 ++ unsigned long endaddress, i, j; ++ endaddress = from + len -1; ++ from &= ~(32-1); ++ endaddress &= ~(32-1); ++ for (i = from; i <= endaddress; i += 32) ++ asm("mcr p15, 0, %0, c7, c6, 1"::"r"(i)); ++ ++ asm( "mrc p15, 0, %0, c2, c0, 0\n" ++ "mov %0, %0\n" ++ "sub pc, pc #4" ++ :"=r"(j)); ++#else ++ consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE); ++#endif ++} ++ ++ ++struct map_info pxa27x_map = { ++ .name = "PXA27x flash", ++ .size = WINDOW_SIZE, ++ .phys = WINDOW_ADDR, ++ .inval_cache = &pxa27x_map_inval_cache, ++}; ++ ++#if defined CONFIG_MTD_EZX_A780_ALTERNATE ++static struct mtd_partition pxa27x_partitions[] = { ++ { ++ .name = "Bootloader (RO)", ++ .size = 0x00020000, ++ .offset = 0, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "Bootloader 2", ++ .size = 0x00020000, ++ .offset = 0x00020000, ++ } , { ++ .name = "Kernel 1", ++ .size = 0x000e0000, // 896KB ++ .offset = 0x00040000, ++ } , { ++ .name = "rootfs", ++ .size = 0x01760000, ++ .offset = 0x00120000, ++ } , { ++ .name = "Kernel 2", ++ .size = 0x00180000, // 1.5MB ++ .offset = 0x01880000, ++ } , { ++ .name = "VFM_Filesystem", ++ .size = 0x005a0000, ++ .offset = 0x01a00000, ++ } , { ++ .name = "setup", ++ .size = 0x00020000, ++ .offset = 0x01fa0000, ++ } , { ++ .name = "Logo", ++ .size = 0x00020000, ++ .offset = 0x01fc0000, ++ }, ++}; ++#elif defined CONFIG_MTD_EZX_A780 ++static struct mtd_partition pxa27x_partitions[] = { ++ { ++ .name = "Bootloader", ++ .size = 0x00020000, ++ .offset = 0, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "Kernel", ++ .size = 0x000e0000, ++ .offset = 0x00020000, ++ } , { ++ .name = "rootfs", ++ .size = 0x018e0000, ++ .offset = 0x00120000, ++ } , { ++ .name = "VFM_Filesystem", ++ .size = 0x00580000, ++ .offset = 0x01a00000, ++ } , { ++ .name = "setup", ++ .size = 0x00020000, ++ .offset = 0x01fa0000, ++ } , { ++ .name = "Logo", ++ .size = 0x00020000, ++ .offset = 0x01fc0000, ++ }, ++}; ++#else ++#error "please define partition for this PXA27x implementation" ++#endif ++ ++ ++static struct mtd_info *mymtd; ++static struct mtd_partition *parsed_parts; ++ ++static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; ++ ++static int __init init_pxa27x(void) ++{ ++ struct mtd_partition *parts; ++ int nb_parts = 0; ++ int parsed_nr_parts = 0; ++ char *part_type = "static"; ++ ++ pxa27x_map.bankwidth = (BOOT_DEF & 1) ? 2 : 4; ++ ++ printk("Probing PXA27x flash at physical address 0x%08x (%d-bit bankwidth)\n", ++ WINDOW_ADDR, pxa27x_map.bankwidth * 8); ++ pxa27x_map.virt = ioremap(pxa27x_map.phys, pxa27x_map.size); ++ ++ if (!pxa27x_map.virt) { ++ printk("Failed to ioremap\n"); ++ return -EIO; ++ } ++ ++ mymtd = do_map_probe("cfi_probe", &pxa27x_map); ++ if (!mymtd) { ++ iounmap((void *)pxa27x_map.virt); ++ return -ENXIO; ++ } ++ mymtd->owner = THIS_MODULE; ++ ++#if 0 ++ /* ioremap the first flash chip as cacheable */ ++ pxa27x_map.cached = ioremap_cached(pxa27x_map.phys, pxa27x_map.size); ++ if (!pxa27x_map.cached) { ++ printk("Failed to do cacheable-ioremap\n"); ++ iounmap((void *)pxa27x_map.virt); ++ return -EIO; ++ } ++#endif ++ simple_map_init(&pxa27x_map); ++ ++ if (parsed_nr_parts == 0) { ++ int ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0); ++ ++ if (ret > 0) { ++ part_type = "RedBoot"; ++ parsed_nr_parts = ret; ++ } ++ } ++ ++ if (parsed_nr_parts > 0) { ++ parts = parsed_parts; ++ nb_parts = parsed_nr_parts; ++ } else { ++ parts = pxa27x_partitions; ++ nb_parts = ARRAY_SIZE(pxa27x_partitions); ++ } ++ ++ if (nb_parts) { ++ printk(KERN_NOTICE "Using %s partition definition\n", part_type); ++ add_mtd_partitions(mymtd, parts, nb_parts); ++ } else { ++ add_mtd_device(mymtd); ++ } ++#if 0 ++ if (ret = ezx_partition_init()) ++#endif ++ return 0; ++} ++ ++static void __exit cleanup_pxa27x(void) ++{ ++ if (mymtd) { ++ del_mtd_partitions(mymtd); ++ map_destroy(mymtd); ++ if (parsed_parts) ++ kfree(parsed_parts); ++ } ++ if (pxa27x_map.virt) ++ iounmap((void *)pxa27x_map.virt); ++ if (pxa27x_map.cached) ++ iounmap((void *)pxa27x_map.cached); ++ return; ++} ++ ++module_init(init_pxa27x); ++module_exit(cleanup_pxa27x); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); ++MODULE_DESCRIPTION("MTD map driver for Motorola EZX platform"); diff --git a/packages/linux/linux-ezx-2.6.20.7/ezx-pcap.patch b/packages/linux/linux-ezx-2.6.20.7/ezx-pcap.patch new file mode 100644 index 0000000000..22c5d44f36 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/ezx-pcap.patch @@ -0,0 +1,1197 @@ +Index: linux-2.6.20.7/arch/arm/mach-pxa/ezx-pcap.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/arch/arm/mach-pxa/ezx-pcap.c 2007-04-21 08:26:37.000000000 -0300 +@@ -0,0 +1,411 @@ ++/* Driver for Motorola PCAP2 as present in EZX phones ++ * ++ * This is both a SPI device driver for PCAP itself, as well as ++ * an IRQ demultiplexer for handling PCAP generated events such as ++ * headphone jack sense by downstream drivers. ++ * ++ * (C) 2006 by Harald Welte <laforge@openezx.org> ++ * ++ * 2007, April - Daniel Ribeiro <drwyrm@gmail.com> ++ * Altered to work with corgi's SSP code. ++ * Fixed irq handling routine. ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/platform_device.h> ++#include <linux/interrupt.h> ++#include <linux/kernel_stat.h> ++ ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++ ++#include <asm/arch/ssp.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/ezx-pcap.h> ++#include <asm/arch/irqs.h> ++#include <asm/mach/irq.h> ++ ++#include "ezx.h" ++ ++#if 0 ++#define DEBUGP(x, args...) printk(x, ## args) ++#else ++#define DEBUGP(x, args...) ++#endif ++ ++extern unsigned long ezx_ssp_pcap_putget(ulong); ++ ++int ezx_pcap_write(u_int8_t reg_num, u_int32_t value) ++{ ++ value &= SSP_PCAP_REGISTER_VALUE_MASK; ++ value |= SSP_PCAP_REGISTER_WRITE_OP_BIT ++ | (reg_num<<SSP_PCAP_REGISTER_ADDRESS_SHIFT); ++ ++ local_irq_disable(); ++ ezx_ssp_pcap_putget(value); ++ local_irq_enable(); ++ ++ DEBUGP("pcap write r%x: 0x%08x\n", reg_num, value); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_write); ++ ++int ezx_pcap_read(u_int8_t reg_num, u_int32_t *value) ++{ ++ u_int32_t frame = SSP_PCAP_REGISTER_READ_OP_BIT ++ | (reg_num<<SSP_PCAP_REGISTER_ADDRESS_SHIFT); ++ ++ local_irq_disable(); ++ *value = ezx_ssp_pcap_putget(frame); ++ local_irq_enable(); ++ ++ DEBUGP("pcap read r%x: 0x%08x\n", reg_num, *value); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_read); ++ ++int ezx_pcap_bit_set(u_int32_t sspPcapBit, u_int8_t to) ++{ ++ int ret; ++ u_int32_t tmp; ++ u_int32_t bit = (sspPcapBit & SSP_PCAP_REGISTER_VALUE_MASK); ++ u_int8_t reg_num = (sspPcapBit & SSP_PCAP_REGISTER_ADDRESS_MASK) ++ >> SSP_PCAP_REGISTER_ADDRESS_SHIFT; ++ ++ ret = ezx_pcap_read(reg_num, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ if (to == 0) ++ tmp &= ~bit; ++ else ++ tmp |= bit; ++ ++ return ezx_pcap_write(reg_num, tmp); ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_bit_set); ++ ++int ezx_pcap_read_bit(u_int32_t bit) ++{ ++ int ret; ++ u_int32_t tmp; ++ u_int8_t reg_num = (bit & SSP_PCAP_REGISTER_ADDRESS_MASK) ++ >> SSP_PCAP_REGISTER_ADDRESS_SHIFT; ++ ++ ret = ezx_pcap_read(reg_num, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ return tmp & (bit & SSP_PCAP_REGISTER_VALUE_MASK); ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_read_bit); ++ ++ ++static int ezx_pcap_vibrator_level(u_int32_t bit) ++{ ++ /* FIXME */ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_vibrator_level); ++ ++ ++static int pcap_init(void) ++{ ++ /* initialize registers */ ++ /* FIXME: this should be board-level, not chip-level */ ++ /* implement a per board pcap init reg array? */ ++ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB4VI, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB4VM, 0); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB1VI, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB1VM, 0); ++ // disable all interrupts ++ //ezx_pcap_write(SSP_PCAP_ADJ_MSR_REGISTER, 0x03ffffff); ++ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL, 1); ++ ezx_pcap_vibrator_level(PCAP_VIBRATOR_VOLTAGE_LEVEL3); ++ ezx_pcap_vibrator_level(PCAP_VIBRATOR_VOLTAGE_LEVEL3); ++ ++ /* set SW1 sleep to keep SW1 1.3v in sync mode */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE10, 0); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE11, 0); ++ /* SW1 active in sync mode */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE00, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE01, 0); ++ /* at SW1 -core voltage to 1.30V */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW10_DVS, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW11_DVS, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW12_DVS, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW13_DVS, 0); ++ ++ /* when STANDY2 PIN ACTIVE (high) set V3-- sram V8 -- pll off */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V3_STBY, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V3_LOWPWR, 0); ++ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V8_STBY, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V8_LOWPWR, 0); ++ ++ /* when STANDY2 PIN ACTIVE (high) set V4-- lcd only for e680 V6 --- ++ * camera for e680 */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V4_STBY, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V4_LOWPWR, 1); ++ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V6_STBY, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V6_LOWPWR, 0); ++ ++ /* set Vc to low power mode when AP sleep */ ++ //SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VC_STBY); ++ ++ /* set VAUX2 to voltage 2.775V and low power mode when AP sleep */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_1, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_0, 0); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_STBY, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_LOWPWR, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN, 1); ++ ++ PGSR(GPIO34_TXENB) |= GPIO_bit(GPIO34_TXENB); ++ ++ return 0; ++} ++/* MMC/SD specific functions */ ++ ++void ezx_pcap_mmcsd_voltage(u_int32_t bits) ++{ ++ unsigned int tmp; ++ ezx_pcap_read(SSP_PCAP_ADJ_AUX_VREG_REGISTER, &tmp); ++#if defined(CONFIG_PXA_EZX_E680) ++ tmp &= 0xffffff9f; /* zero all vaux2 bits */ ++ tmp |= (bits & 0x3) << 5; ++#elif defined(CONFIG_PXA_EZX_A780) ++ tmp &= 0xfffff0ff; /* zero all vaux3 bits */ ++ tmp |= (bits & 0xf) << 8; ++#endif ++ ezx_pcap_write(SSP_PCAP_ADJ_AUX_VREG_REGISTER, tmp); ++} ++EXPORT_SYMBOL(ezx_pcap_mmcsd_voltage); ++ ++int ezx_pcap_mmcsd_power(int on) ++{ ++ if (on) { ++#if defined(CONFIG_PXA_EZX_E680) ++ return ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN, 1); ++#else ++ return ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_EN, 1); ++#endif ++ } else { ++#if defined(CONFIG_PXA_EZX_E680) ++ return ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN, 0); ++#else ++ return ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_EN, 0); ++#endif ++ } ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_mmcsd_power); ++ ++/* IRQ Handling */ ++ ++/* Array indexed by BIT POSITION of PCAP register, returns IRQ number */ ++static unsigned int pcap2irq[] = { ++ [0] = EZX_IRQ_ADCDONE, ++ [1] = EZX_IRQ_TS, ++ [2] = 0, /* 1HZ */ ++ [3] = 0, /* WI */ ++ [4] = 0, /* WI */ ++ [5] = 0, /* TODA */ ++ [6] = EZX_IRQ_USB4V, ++ [7] = 0, /* ONOFF */ ++ [8] = 0, /* ONOFF2 */ ++ [9] = EZX_IRQ_USB1V, ++ [10] = 0, /* MOBPORT */ ++ [11] = EZX_IRQ_MIC, ++ [12] = EZX_IRQ_HEADJACK, ++ [13] = 0, /* ST */ ++ [14] = 0, /* PC */ ++ [15] = 0, /* WARM */ ++ [16] = 0, /* EOL */ ++ [17] = 0, /* CLK */ ++ [18] = 0, /* SYS_RST */ ++ [19] = 0, ++ [20] = EZX_IRQ_ADCDONE2, ++ [21] = 0, /* SOFT_RESET */ ++ [22] = 0, /* MNEXB */ ++}; ++ ++/* Array indexed by IRQ NUMBER, returns PCAP absolute value */ ++static unsigned int irq2pcap[] = { ++ [EZX_IRQ_ADCDONE] = SSP_PCAP_ADJ_BIT_ISR_ADCDONEI, ++ [EZX_IRQ_TS] = SSP_PCAP_ADJ_BIT_ISR_TSI, ++ [EZX_IRQ_USB4V] = SSP_PCAP_ADJ_BIT_ISR_USB4VI, ++ [EZX_IRQ_USB1V] = SSP_PCAP_ADJ_BIT_ISR_USB1VI, ++ [EZX_IRQ_HEADJACK] = SSP_PCAP_ADJ_BIT_ISR_A1I, ++ [EZX_IRQ_MIC] = SSP_PCAP_ADJ_BIT_ISR_MB2I, ++ [EZX_IRQ_ADCDONE2] = SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I, ++}; ++ ++static void pcap_ack_irq(unsigned int irq) ++{ ++ DEBUGP("pcap_ack_irq: %u\n", irq); ++ ezx_pcap_write(SSP_PCAP_ADJ_ISR_REGISTER, irq2pcap[irq]); ++} ++ ++static void pcap_mask_irq(unsigned int irq) ++{ ++ u_int32_t reg; ++ ++ DEBUGP("pcap_mask_irq: %u\n", irq); ++ ++ /* this needs to be atomic... but we're not on SMP so it is */ ++ ezx_pcap_read(SSP_PCAP_ADJ_MSR_REGISTER, ®); ++ reg |= irq2pcap[irq]; ++ ezx_pcap_write(SSP_PCAP_ADJ_MSR_REGISTER, reg); ++} ++ ++static void pcap_unmask_irq(unsigned int irq) ++{ ++ u_int32_t tmp; ++ DEBUGP("pcap_unmask_irq: %u\n", irq); ++ ++ /* this needs to be atomic... but we're not on SMP so it is */ ++ ezx_pcap_read(SSP_PCAP_ADJ_MSR_REGISTER, &tmp); ++ tmp &= ~irq2pcap[irq]; ++ ezx_pcap_write(SSP_PCAP_ADJ_MSR_REGISTER, tmp); ++} ++ ++static struct irq_chip pcap_chip = { ++ .ack = pcap_ack_irq, ++ .mask = pcap_mask_irq, ++ .unmask = pcap_unmask_irq, ++}; ++ ++/* handler for interrupt received from PCAP via GPIO */ ++static void pcap_irq_demux_handler(unsigned int irq, struct irq_desc *desc) ++{ ++ int i; ++ const unsigned int cpu = smp_processor_id(); ++ u_int32_t reg; ++ ++ DEBUGP("pcap_irq_demux_handler(%u,,) entered\n", irq); ++ ++ spin_lock(&desc->lock); ++ ++ desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); ++ ++ if (unlikely(desc->status & IRQ_INPROGRESS)) { ++ DEBUGP("irq busy, masking it off\n"); ++ desc->status |= (IRQ_PENDING | IRQ_MASKED); ++ desc->chip->mask(irq); ++ desc->chip->ack(irq); ++ goto out_unlock; ++ } ++ ++ kstat_cpu(cpu).irqs[irq]++; ++ desc->status |= IRQ_INPROGRESS; ++ ++ do { ++ if (unlikely((desc->status & ++ (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) == ++ (IRQ_PENDING | IRQ_MASKED))) { ++ DEBUGP("dealing with pending IRQ, unmasking\n"); ++ desc->chip->unmask(irq); ++ desc->status &= ~IRQ_MASKED; ++ } ++ ++ desc->status &= ~IRQ_PENDING; ++ spin_unlock(&desc->lock); ++ ++ ezx_pcap_read(SSP_PCAP_ADJ_ISR_REGISTER, ®); ++ DEBUGP("pcap_irq_demux_handler: ISR=0x%08x\n", reg); ++ ++ for (i = ARRAY_SIZE(pcap2irq)-1; i >= 0; i--) { ++ unsigned int pirq = pcap2irq[i]; ++ if (pirq == 0) ++ continue; ++ ++ if (reg & (1 << i)) { ++ struct irq_desc *subdesc; ++ DEBUGP("found irq %u\n", pirq); ++ subdesc = irq_desc + pirq; ++ ++ // acknowledge pcap irq ++ // do just one pcap irq each time ++ subdesc->chip->ack(pirq); ++ i = 0; ++ ++ handle_IRQ_event(pirq, subdesc->action); ++ } ++ } ++ spin_lock(&desc->lock); ++ ++ } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING); ++ ++ desc->status &= ~IRQ_INPROGRESS; ++ ++out_unlock: ++ spin_unlock(&desc->lock); ++} ++ ++static int ezx_pcap_remove(struct platform_device *pdev) ++{ ++ int irq; ++ DEBUGP("exz_pcap_remove entered\n"); ++ ++ set_irq_chained_handler(IRQ_GPIO1, NULL); ++ ++ for (irq = EZX_IRQ(0); irq <= EZX_IRQ(6); irq++) { ++ set_irq_chip(irq, NULL); ++ set_irq_handler(irq, NULL); ++ set_irq_flags(irq, 0); ++ } ++ ++ return 0; ++} ++ ++static int __init ezx_pcap_probe(struct platform_device *pdev) ++{ ++ unsigned int irq; ++ DEBUGP("ezx_pcap_probe entered\n"); ++ ++ pcap_init(); ++ ++ set_irq_type(IRQ_GPIO1, IRQT_RISING); ++ /* set up interrupt demultiplexing code for PCAP2 irqs */ ++ for (irq = EZX_IRQ(0); irq <= EZX_IRQ(6); irq++) { ++ set_irq_chip(irq, &pcap_chip); ++ set_irq_handler(irq, handle_edge_irq); ++ set_irq_flags(irq, IRQF_VALID); ++ } ++ set_irq_chained_handler(IRQ_GPIO1, pcap_irq_demux_handler); ++ ++ printk("PCAP2 SSP driver registered.\n"); ++ ++ return 0; ++} ++ ++static struct platform_driver ezxpcap_driver = { ++ .probe = ezx_pcap_probe, ++ .remove = ezx_pcap_remove, ++ .driver = { ++ .name = "ezx-pcap", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init ezx_pcap_init(void) ++{ ++ DEBUGP("ezx_pcap_init entered\n"); ++ return platform_driver_register(&ezxpcap_driver); ++} ++ ++static void __exit ezx_pcap_exit(void) ++{ ++ return platform_driver_unregister(&ezxpcap_driver); ++} ++ ++module_init(ezx_pcap_init); ++module_exit(ezx_pcap_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte"); ++MODULE_DESCRIPTION("SPI Driver for Motorola PCAP2"); ++ +Index: linux-2.6.20.7/include/asm-arm/arch-pxa/ezx-pcap.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/include/asm-arm/arch-pxa/ezx-pcap.h 2007-04-21 08:26:37.000000000 -0300 +@@ -0,0 +1,665 @@ ++/* (c) Copyright Motorola Beijing 2002 all rights reserved. ++ ++ Project Name : EZX ++ Project No. : ++ Title : ++ File Name : ++ Description : ++ ++ ************** REVISION HISTORY ********************************************** ++ Date Author Reference ++ ======== ========== ========================== ++ 2002-07-01 weiqiang lin create ++*/ ++#ifndef SSP_PCAP_H ++#define SSP_PCAP_H ++ ++#define SSP_vibrate_start_command() SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN); \ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN) ++ ++#define SSP_vibrate_stop_command() SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN); \ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN) ++ ++#define SSP_PCAP_REGISTER_VALUE_LENGTH 16 ++ ++#define SSP_PCAP_REGISTER_WRITE_OP_BIT 0x80000000 ++#define SSP_PCAP_REGISTER_READ_OP_BIT 0x00000000 ++ ++#define SSP_PCAP_REGISTER_VALUE_UP_WORD_MASK 0xffff0000 ++#define SSP_PCAP_REGISTER_VALUE_DOWN_WORD_MASK 0x0000ffff ++ ++#define SSP_PCAP_REGISTER_VALUE_MASK 0x01ffffff ++#define SSP_PCAP_REGISTER_VALUE_MASK 0x01ffffff ++#define SSP_PCAP_REGISTER_ADDRESS_MASK 0x7c000000 ++#define SSP_PCAP_REGISTER_ADDRESS_SHIFT 26 ++#define SSP_PCAP_REGISTER_NUMBER 32 ++ ++#define SSP_PCAP_ADC_START_VALUE_SET_MASK 0xfffffc00 ++#define SSP_PCAP_ADC_START_VALUE 0x000001dd ++ ++ ++#define SSP_PCAP_PHONE_CDC_CLOCK_MASK 0x000001c0 ++#define SSP_PCAP_STEREO_SAMPLE_RATE_MASK 0x00000f00 ++#define SSP_PCAP_STEREO_BCLK_TIME_SLOT_MASK 0x00018000 ++#define SSP_PCAP_STEREO_CLOCK_MASK 0x0000001c ++#define SSP_PCAP_DIGITAL_AUDIO_MODE_MASK 0x00006000 ++#define SSP_PCAP_TOUCH_PANEL_POSITION_DETECT_MODE_MASK 0x000e0000 ++#define SSP_PCAP_MONO_PGA_MASK 0x00180000 ++ ++#define SSP_PCAP_VIBRATOR_VOLTAGE_LEVEL_MASK 0x00300000 ++ ++#define SSP_PCAP_AUDIO_IN_GAIN_MASK 0x0000001f ++#define SSP_PCAP_AUDIO_IN_GAIN_SHIFT 0 ++#define SSP_PCAP_AUDIO_OUT_GAIN_MASK 0x0001e000 ++#define SSP_PCAP_AUDIO_OUT_GAIN_SHIFT 13 ++ ++ ++#define SSP_PCAP_ADD1_VALUE_MASK 0x000003ff ++#define SSP_PCAP_ADD1_VALUE_SHIFT 0 ++#define SSP_PCAP_ADD2_VALUE_MASK 0x000ffc00 ++#define SSP_PCAP_ADD2_VALUE_SHIFT 10 ++ ++ ++#define PCAP_AUDIO_IN_GAIN_MAX_VALUE 31 ++#define PCAP_AUDIO_OUT_GAIN_MAX_VALUE 15 ++ ++#define PCAP_CLEAR_INTERRUPT_REGISTER 0x00141fdf ++#define PCAP_MASK_ALL_INTERRUPT 0x0013ffff ++ ++#define SSP_PCAP_TS_KEEPER_TIMER 100 /* 1 second */ ++#define START_ADC_DELAY_TIMER 1991 /* 540 us */ ++ ++#define SSP_SEND_PM_ALART_INTERVAL 1000 *HZ/1000 /* 1 second */ ++#define SSP_SEND_MSG_USB_ACCESSORY_INFO_DEBOUNCE 200 *HZ/1000 /* 200ms */ ++ ++struct ssp_interrupt_info ++{ ++ u32 type; ++ u32 status; ++ void* privdata; ++}; ++ ++#ifndef U8 ++#define U8 unsigned char ++#endif ++ ++#ifndef U32 ++#define U32 unsigned long ++#endif ++ ++#ifndef U16 ++#define U16 unsigned short ++#endif ++ ++#ifndef P_U16 ++#define P_U16 U16* ++#endif ++ ++#ifndef P_U32 ++#define P_U32 U32* ++#endif ++ ++#define SSP_SELECT_BUFFER (volatile unsigned long *)(0xf4000000) ++ ++#define SSP_SR_RNE 0x00000008 ++#define SSP_PCAP_BASE 0x00001000 ++/************************ STRUCTURES, ENUMS, AND TYPEDEFS **************************/ ++typedef enum accessoryStatus ++{ ++ ACCESSORY_DEVICE_STATUS_DETACHED = 0, ++ ACCESSORY_DEVICE_STATUS_ATTACHED , ++ ACCESSORY_DEVICE_STATUS_UNKNOW =0x000000ff ++}ACCESSORY_DEVICE_STATUS; ++ ++typedef enum accessoryType ++{ ++ ACCESSORY_DEVICE_NONE = 0, ++ ACCESSORY_DEVICE_SERIAL_PORT , ++ ACCESSORY_DEVICE_USB_PORT , ++ ACCESSORY_DEVICE_UNKNOW =0x000000ff ++}ACCESSORY_TYPE; ++ ++typedef enum pcapReturnStatus ++{ ++ SSP_PCAP_SUCCESS = 0, ++ SSP_PCAP_ERROR_REGISTER = SSP_PCAP_BASE+1, ++ SSP_PCAP_ERROR_VALUE = SSP_PCAP_BASE+2, ++ ++ SSP_PCAP_NOT_RUN = SSP_PCAP_BASE+0xff ++}SSP_PCAP_STATUS; ++ ++typedef enum pcapPortType ++{ ++ SSP_PCAP_SERIAL_PORT = 0x00000000, ++ SSP_PCAP_LOW_USB_PORT = 0x00000001, ++ SSP_PCAP_HIGH_USB_PORT = 0x00000002, ++ SSP_PCAP_UNKNOW_PORT = 0x000000ff ++}SSP_PCAP_PORT_TYPE; ++ ++typedef enum pcapInitDriverType ++{ ++ SSP_PCAP_TS_OPEN = 0x00000000, ++ SSP_PCAP_AUDIO_OPEN = 0x00000001, ++ SSP_PCAP_UNKNOW_DRIVER_OPEN = 0x000000ff ++}SSP_PCAP_INIT_DRIVER_TYPE; ++ ++ ++typedef enum pcapReturnBitStatus ++{ ++ SSP_PCAP_BIT_ZERO = 0x00000000, ++ SSP_PCAP_BIT_ONE = 0x00000001, ++ SSP_PCAP_BIT_ERROR = 0xff000000 ++}SSP_PCAP_BIT_STATUS; ++ ++typedef enum pcapCDCClkType ++{ ++ PCAP_CDC_CLK_IN_13M0 = 0x00000000, ++ PCAP_CDC_CLK_IN_15M36 = 0x00000040, ++ PCAP_CDC_CLK_IN_16M8 = 0x00000080, ++ PCAP_CDC_CLK_IN_19M44 = 0x000000c0, ++ PCAP_CDC_CLK_IN_26M0 = 0x00000100 ++}PHONE_CDC_CLOCK_TYPE; ++ ++typedef enum pcapST_SR ++{ ++ PCAP_ST_SAMPLE_RATE_8K = 0x00000000, ++ PCAP_ST_SAMPLE_RATE_11K = 0x00000100, ++ PCAP_ST_SAMPLE_RATE_12K = 0x00000200, ++ PCAP_ST_SAMPLE_RATE_16K = 0x00000300, ++ PCAP_ST_SAMPLE_RATE_22K = 0x00000400, ++ PCAP_ST_SAMPLE_RATE_24K = 0x00000500, ++ PCAP_ST_SAMPLE_RATE_32K = 0x00000600, ++ PCAP_ST_SAMPLE_RATE_44K = 0x00000700, ++ PCAP_ST_SAMPLE_RATE_48K = 0x00000800 ++}ST_SAMPLE_RATE_TYPE; ++ ++typedef enum pcapST_BCLK ++{ ++ PCAP_ST_BCLK_SLOT_16 = 0x00000000, ++ PCAP_ST_BCLK_SLOT_8 = 0x00008000, ++ PCAP_ST_BCLK_SLOT_4 = 0x00010000, ++ PCAP_ST_BCLK_SLOT_2 = 0x00018000, ++}ST_BCLK_TIME_SLOT_TYPE; ++ ++typedef enum pcapST_CLK ++{ ++ PCAP_ST_CLK_PLL_CLK_IN_13M0 = 0x00000000, ++ PCAP_ST_CLK_PLL_CLK_IN_15M36 = 0x00000004, ++ PCAP_ST_CLK_PLL_CLK_IN_16M8 = 0x00000008, ++ PCAP_ST_CLK_PLL_CLK_IN_19M44 = 0x0000000c, ++ PCAP_ST_CLK_PLL_CLK_IN_26M0 = 0x00000010, ++ PCAP_ST_CLK_PLL_CLK_IN_EXT_MCLK = 0x00000014, ++ PCAP_ST_CLK_PLL_CLK_IN_FSYNC = 0x00000018, ++ PCAP_ST_CLK_PLL_CLK_IN_BITCLK = 0x0000001c ++}ST_CLK_TYPE; ++ ++typedef enum pcapDigitalAudioInterfaceMode ++{ ++ PCAP_DIGITAL_AUDIO_INTERFACE_NORMAL = 0x00000000, ++ PCAP_DIGITAL_AUDIO_INTERFACE_NETWORK = 0x00002000, ++ PCAP_DIGITAL_AUDIO_INTERFACE_I2S = 0x00004000 ++}DIG_AUD_MODE_TYPE; ++ ++typedef enum pcapMono ++{ ++ PCAP_MONO_PGA_R_L_STEREO = 0x00000000, ++ PCAP_MONO_PGA_RL = 0x00080000, ++ PCAP_MONO_PGA_RL_3DB = 0x00100000, ++ PCAP_MONO_PGA_RL_6DB = 0x00180000 ++}MONO_TYPE; ++ ++typedef enum pcapVibratorVoltageLevel ++{ ++ PCAP_VIBRATOR_VOLTAGE_LEVEL0 = 0x00000000, ++ PCAP_VIBRATOR_VOLTAGE_LEVEL1 = 0x00100000, ++ PCAP_VIBRATOR_VOLTAGE_LEVEL2 = 0x00200000, ++ PCAP_VIBRATOR_VOLTAGE_LEVEL3 = 0x00300000 ++}VibratorVoltageLevel_TYPE; ++ ++typedef enum pcapTouchScreenMode ++{ ++ PCAP_TS_POSITION_X_MEASUREMENT = 0x00000000, ++ PCAP_TS_POSITION_XY_MEASUREMENT = 0x00020000, ++ PCAP_TS_PRESSURE_MEASUREMENT = 0x00040000, ++ PCAP_TS_PLATE_X_MEASUREMENT = 0x00060000, ++ PCAP_TS_PLATE_Y_MEASUREMENT = 0x00080000, ++ PCAP_TS_STANDBY_MODE = 0x000a0000, ++ PCAP_TS_NONTS_MODE = 0x000c0000 ++}TOUCH_SCREEN_DETECT_TYPE; ++ ++typedef enum pcapADJRegister ++{ ++ SSP_PCAP_ADJ_ISR_REGISTER = 0x00, ++ SSP_PCAP_ADJ_MSR_REGISTER = 0x01, ++ SSP_PCAP_ADJ_PSTAT_REGISTER = 0x02, ++ SSP_PCAP_ADJ_VREG2_REGISTER = 0x06, ++ SSP_PCAP_ADJ_AUX_VREG_REGISTER = 0x07, ++ SSP_PCAP_ADJ_BATT_DAC_REGISTER = 0x08, ++ SSP_PCAP_ADJ_ADC1_REGISTER = 0x09, ++ SSP_PCAP_ADJ_ADC2_REGISTER = 0x0a, ++ SSP_PCAP_ADJ_AUD_CODEC_REGISTER = 0x0b, ++ SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER = 0x0c, ++ SSP_PCAP_ADJ_ST_DAC_REGISTER = 0x0d, ++ SSP_PCAP_ADJ_BUSCTRL_REGISTER = 0x14, ++ SSP_PCAP_ADJ_PERIPH_REGISTER = 0x15, ++ SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER = 0x18, ++ SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER = 0x1a, ++ SSP_PCAP_ADJ_GP_REG_REGISTER = 0x1b ++}SSP_PCAP_SECONDARY_PROCESSOR_REGISTER; ++ ++typedef enum pcapADJBit_SetType ++{ ++ SSP_PCAP_ADJ_BIT_ISR_ADCDONEI = 0x00000001, ++ SSP_PCAP_ADJ_BIT_ISR_TSI = 0x00000002, ++ SSP_PCAP_ADJ_BIT_ISR_1HZI = 0x00000004, ++ SSP_PCAP_ADJ_BIT_ISR_WHI = 0x00000008, ++ SSP_PCAP_ADJ_BIT_ISR_WLI = 0x00000010, ++ SSP_PCAP_ADJ_BIT_ISR_TODAI = 0x00000020, ++ SSP_PCAP_ADJ_BIT_ISR_USB4VI = 0x00000040, ++ SSP_PCAP_ADJ_BIT_ISR_ONOFFI = 0x00000080, ++ SSP_PCAP_ADJ_BIT_ISR_ONOFF2I = 0x00000100, ++ SSP_PCAP_ADJ_BIT_ISR_USB1VI = 0x00000200, ++ SSP_PCAP_ADJ_BIT_ISR_MOBPORTI = 0x00000400, ++ SSP_PCAP_ADJ_BIT_ISR_MB2I = 0x00000800, ++ SSP_PCAP_ADJ_BIT_ISR_A1I = 0x00001000, ++ SSP_PCAP_ADJ_BIT_ISR_STI = 0x00002000, ++ SSP_PCAP_ADJ_BIT_ISR_PCI = 0x00004000, ++ SSP_PCAP_ADJ_BIT_ISR_WARMI = 0x00008000, ++ SSP_PCAP_ADJ_BIT_ISR_EOLI = 0x00010000, ++ SSP_PCAP_ADJ_BIT_ISR_CLKI = 0x00020000, ++ SSP_PCAP_ADJ_BIT_ISR_SYS_RSTI = 0x00040000, ++ SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I = 0x00100000, ++ SSP_PCAP_ADJ_BIT_ISR_SOFT_RESETI = 0x00200000, ++ SSP_PCAP_ADJ_BIT_ISR_MNEXBI = 0x00400000, ++ ++ SSP_PCAP_ADJ_BIT_MSR_ADCDONEM = 0x04000001, ++ SSP_PCAP_ADJ_BIT_MSR_TSM = 0x04000002, ++ SSP_PCAP_ADJ_BIT_MSR_1HZM = 0x04000004, ++ SSP_PCAP_ADJ_BIT_MSR_WHM = 0x04000008, ++ SSP_PCAP_ADJ_BIT_MSR_WLM = 0x04000010, ++ SSP_PCAP_ADJ_BIT_MSR_TODAM = 0x04000020, ++ SSP_PCAP_ADJ_BIT_MSR_USB4VM = 0x04000040, ++ SSP_PCAP_ADJ_BIT_MSR_ONOFFM = 0x04000080, ++ SSP_PCAP_ADJ_BIT_MSR_ONOFF2M = 0x04000100, ++ SSP_PCAP_ADJ_BIT_MSR_USB1VM = 0x04000200, ++ SSP_PCAP_ADJ_BIT_MSR_MOBPORTM = 0x04000400, ++ SSP_PCAP_ADJ_BIT_MSR_MB2M = 0x04000800, ++ SSP_PCAP_ADJ_BIT_MSR_A1M = 0x04001000, ++ SSP_PCAP_ADJ_BIT_MSR_STM = 0x04002000, ++ SSP_PCAP_ADJ_BIT_MSR_PCM = 0x04004000, ++ SSP_PCAP_ADJ_BIT_MSR_WARMM = 0x04008000, ++ SSP_PCAP_ADJ_BIT_MSR_EOLM = 0x04010000, ++ SSP_PCAP_ADJ_BIT_MSR_CLKM = 0x04020000, ++ SSP_PCAP_ADJ_BIT_MSR_SYS_RSTM = 0x04040000, ++ SSP_PCAP_ADJ_BIT_MSR_ADCDONE2M = 0x04100000, ++ SSP_PCAP_ADJ_BIT_MSR_SOFT_RESETM = 0x04200000, ++ SSP_PCAP_ADJ_BIT_MSR_MNEXBM = 0x04400000, ++ ++ SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V = 0x08000040, ++ SSP_PCAP_ADJ_BIT_PSTAT_ONOFFSNS = 0x08000080, ++ SSP_PCAP_ADJ_BIT_PSTAT_ONOFFSNS2 = 0x08000100, ++ SSP_PCAP_ADJ_BIT_PSTAT_USBDET_1V = 0x08000200, ++ SSP_PCAP_ADJ_BIT_PSTAT_MOBSENSB = 0x08000400, ++ SSP_PCAP_ADJ_BIT_PSTAT_MB2SNS = 0x08000800, ++ SSP_PCAP_ADJ_BIT_PSTAT_A1SNS = 0x08001000, ++ SSP_PCAP_ADJ_BIT_PSTAT_MSTB = 0x08002000, ++ SSP_PCAP_ADJ_BIT_PSTAT_EOL_STAT = 0x08010000, ++ SSP_PCAP_ADJ_BIT_PSTAT_CLK_STAT = 0x08020000, ++ SSP_PCAP_ADJ_BIT_PSTAT_SYS_RST = 0x08040000, ++ SSP_PCAP_ADJ_BIT_PSTAT_BATTFBSNS = 0x08080000, ++ SSP_PCAP_ADJ_BIT_PSTAT_BATT_DET_IN_SNS = 0x08200000, ++ SSP_PCAP_ADJ_BIT_PSTAT_MNEXBSNS = 0x08400000, ++ SSP_PCAP_ADJ_BIT_PSTAT_WARM_SYS_RST = 0x08800000, ++ ++ SSP_PCAP_ADJ_BIT_VREG2_V1_STBY = 0x18000001, ++ SSP_PCAP_ADJ_BIT_VREG2_V2_STBY = 0x18000002, ++ SSP_PCAP_ADJ_BIT_VREG2_V3_STBY = 0x18000004, ++ SSP_PCAP_ADJ_BIT_VREG2_V4_STBY = 0x18000008, ++ SSP_PCAP_ADJ_BIT_VREG2_V5_STBY = 0x18000010, ++ SSP_PCAP_ADJ_BIT_VREG2_V6_STBY = 0x18000020, ++ SSP_PCAP_ADJ_BIT_VREG2_V7_STBY = 0x18000040, ++ SSP_PCAP_ADJ_BIT_VREG2_V8_STBY = 0x18000080, ++ SSP_PCAP_ADJ_BIT_VREG2_V9_STBY = 0x18000100, ++ SSP_PCAP_ADJ_BIT_VREG2_V10_STBY = 0x18000200, ++ SSP_PCAP_ADJ_BIT_VREG2_V1_LOWPWR = 0x18000400, ++ SSP_PCAP_ADJ_BIT_VREG2_V2_LOWPWR = 0x18000800, ++ SSP_PCAP_ADJ_BIT_VREG2_V3_LOWPWR = 0x18001000, ++ SSP_PCAP_ADJ_BIT_VREG2_V4_LOWPWR = 0x18002000, ++ SSP_PCAP_ADJ_BIT_VREG2_V5_LOWPWR = 0x18004000, ++ SSP_PCAP_ADJ_BIT_VREG2_V6_LOWPWR = 0x18008000, ++ SSP_PCAP_ADJ_BIT_VREG2_V7_LOWPWR = 0x18010000, ++ SSP_PCAP_ADJ_BIT_VREG2_V8_LOWPWR = 0x18020000, ++ SSP_PCAP_ADJ_BIT_VREG2_V9_LOWPWR = 0x18040000, ++ SSP_PCAP_ADJ_BIT_VREG2_V10_LOWPWR = 0x18080000, ++ ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_EN = 0x1c000002, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_0 = 0x1c000004, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_1 = 0x1c000008, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN = 0x1c000010, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_0 = 0x1c000020, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_1 = 0x1c000040, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_EN = 0x1c000080, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_0 = 0x1c000100, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_1 = 0x1c000200, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_2 = 0x1c000400, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_3 = 0x1c000800, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX4_EN = 0x1c001000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX4_0 = 0x1c002000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX4_1 = 0x1c004000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VSIM2_EN = 0x1c010000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VSIM_EN = 0x1c020000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VSIM_0 = 0x1c040000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN = 0x1c080000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_0 = 0x1c100000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_1 = 0x1c200000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_STBY = 0x1c400000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_LOWPWR = 0x1c800000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_SW3_STBY = 0x1d000000, ++ ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC0 = 0x20000001, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC1 = 0x20000002, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC2 = 0x20000004, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC3 = 0x20000008, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC4 = 0x20000010, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC5 = 0x20000020, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC6 = 0x20000040, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC7 = 0x20000080, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_B_FDBK = 0x20000100, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EXT_ISENSE = 0x20000200, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN0 = 0x20000400, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN1 = 0x20000800, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN2 = 0x20001000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN3 = 0x20002000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_I_COIN = 0x20004000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_COIN_CH_EN = 0x20008000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_SEL0 = 0x20020000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_SEL1 = 0x20040000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_SEL2 = 0x20080000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_CMP_EN = 0x20100000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_BATT_DET_EN = 0x20200000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_THERMBIAS_CTRL = 0x20400000, ++ ++ SSP_PCAP_ADJ_BIT_ADC1_ADEN = 0x24000001, ++ SSP_PCAP_ADJ_BIT_ADC1_RAND = 0x24000002, ++ SSP_PCAP_ADJ_BIT_ADC1_AD_SEL1 = 0x24000004, ++ SSP_PCAP_ADJ_BIT_ADC1_AD_SEL2 = 0x24000008, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA10 = 0x24000010, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA11 = 0x24000020, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA12 = 0x24000040, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA20 = 0x24000080, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA21 = 0x24000100, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA22 = 0x24000200, ++ SSP_PCAP_ADJ_BIT_ADC1_ATO0 = 0x24000400, ++ SSP_PCAP_ADJ_BIT_ADC1_ATO1 = 0x24000800, ++ SSP_PCAP_ADJ_BIT_ADC1_ATO2 = 0x24001000, ++ SSP_PCAP_ADJ_BIT_ADC1_ATO3 = 0x24002000, ++ SSP_PCAP_ADJ_BIT_ADC1_ATOX = 0x24004000, ++ SSP_PCAP_ADJ_BIT_ADC1_MTR1 = 0x24008000, ++ SSP_PCAP_ADJ_BIT_ADC1_MTR2 = 0x24010000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_M0 = 0x24020000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_M1 = 0x24040000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_M2 = 0x24080000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_REF_LOWPWR = 0x24100000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_REFENB = 0x24200000, ++ SSP_PCAP_ADJ_BIT_ADC1_BATT_I_POLARITY = 0x24400000, ++ SSP_PCAP_ADJ_BIT_ADC1_BATT_I_ADC = 0x24800000, ++ ++ SSP_PCAP_ADJ_BIT_ADC2_ADD10 = 0x28000001, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD11 = 0x28000002, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD12 = 0x28000004, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD13 = 0x28000008, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD14 = 0x28000010, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD15 = 0x28000020, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD16 = 0x28000040, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD17 = 0x28000080, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD18 = 0x28000100, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD19 = 0x28000200, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD20 = 0x28000400, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD21 = 0x28000800, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD22 = 0x28001000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD23 = 0x28002000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD24 = 0x28004000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD25 = 0x28008000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD26 = 0x28010000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD27 = 0x28020000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD28 = 0x28040000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD29 = 0x28080000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADINC1 = 0x28100000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADINC2 = 0x28200000, ++ SSP_PCAP_ADJ_BIT_ADC2_ASC = 0x28400000, ++ ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF = 0x2c000001, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB = 0x2c000002, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF = 0x2c000004, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CD_TS = 0x2c000008, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_DLM = 0x2c000010, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_ADITH = 0x2c000020, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK0 = 0x2c000040, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK1 = 0x2c000080, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK2 = 0x2c000100, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_INV = 0x2c000200, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_INV = 0x2c000400, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET = 0x2c000800, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN = 0x2c001000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN = 0x2c002000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K = 0x2c004000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN = 0x2c008000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL = 0x2c010000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2_MUX = 0x2c020000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG0 = 0x2c040000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG1 = 0x2c080000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG2 = 0x2c100000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG3 = 0x2c200000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG4 = 0x2c400000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG_PRI_ADJ = 0x2c800000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_PRI_ADJ = 0x2c200000, ++ ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1_EN = 0x30000001, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A2_EN = 0x30000002, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A4_EN = 0x30000010, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN = 0x30000020, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN = 0x30000040, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP = 0x30000080, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CDC_SW = 0x30000100, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW = 0x30000200, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW = 0x30000400, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN = 0x30000800, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN = 0x30001000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG0 = 0x30002000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG1 = 0x30004000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG2 = 0x30008000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG3 = 0x30010000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL = 0x30020000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_MONO0 = 0x30080000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_MONO1 = 0x30100000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG_PRI_ADJ = 0x30200000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_MONO_PRI_ADJ = 0x30400000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_RX_PRI_ADJ0 = 0x30800000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_RX_PRI_ADJ1 = 0x31000000, ++ ++ SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC = 0x34000001, ++ SSP_PCAP_ADJ_BIT_ST_DAC_STDET_EN = 0x34000002, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK0 = 0x34000004, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK1 = 0x34000008, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK2 = 0x34000010, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN = 0x34000020, ++ SSP_PCAP_ADJ_BIT_ST_DAC_DF_RESET_ST_DAC = 0x34000040, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN = 0x34000080, ++ SSP_PCAP_ADJ_BIT_ST_DAC_SR0 = 0x34000100, ++ SSP_PCAP_ADJ_BIT_ST_DAC_SR1 = 0x34000200, ++ SSP_PCAP_ADJ_BIT_ST_DAC_SR2 = 0x34000400, ++ SSP_PCAP_ADJ_BIT_ST_DAC_SR3 = 0x34000800, ++ SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_IN_ST_DAC = 0x34001000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_FS0 = 0x34002000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_FS1 = 0x34004000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_BCLK0 = 0x34008000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_BCLK1 = 0x34010000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_INV = 0x34020000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_FS_INV = 0x34040000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL = 0x34080000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_PRI_ADJ = 0x35000000, ++ ++ SSP_PCAP_ADJ_BIT_BUSCTRL_FSENB = 0x50000001, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_SUSPEND = 0x50000002, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU = 0x50000004, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PD = 0x50000008, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN = 0x50000010, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS = 0x50000020, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_MSTR_EN = 0x50000040, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_VBUS_PD_ENB = 0x50000080, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_CURRLIM = 0x50000100, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB = 0x50000200, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_RS232_DIR = 0x50000400, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_SE0_CONN = 0x50000800, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PDM = 0x50001000, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_BUS_PRI_ADJ = 0x51000000, ++ ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL0 = 0x54000001, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL1 = 0x54000002, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL2 = 0x54000004, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL3 = 0x54000008, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL4 = 0x54000010, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_EN = 0x54000020, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_EN = 0x54000040, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL0 = 0x54000080, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL1 = 0x54000100, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL2 = 0x54000200, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL3 = 0x54000400, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL0 = 0x54000800, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL1 = 0x54001000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL2 = 0x54002000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL3 = 0x54004000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_I0 = 0x54008000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_I1 = 0x54010000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_I0 = 0x54020000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_I1 = 0x54040000, ++ SSP_PCAP_ADJ_BIT_PERIPH_SKIP = 0x54080000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL0 = 0x54100000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL1 = 0x54200000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL2 = 0x54400000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL3 = 0x54800000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL4 = 0x55000000, ++ ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_STBY = 0x60000001, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_LOWPWR = 0x60000002, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX3_STBY = 0x60000004, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX3_LOWPWR = 0x60000008, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX4_STBY = 0x60000010, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX4_LOWPWR = 0x60000020, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VSIM_LOWPWR = 0x60000040, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VSIM2_LOWPWR = 0x60000080, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE00 = 0x60000100, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE01 = 0x60000200, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE10 = 0x60000400, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE11 = 0x60000800, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW10_DVS = 0x60001000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW11_DVS = 0x60002000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW12_DVS = 0x60004000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW13_DVS = 0x60008000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE00 = 0x60010000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE01 = 0x60020000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE10 = 0x60040000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE11 = 0x60080000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW20_DVS = 0x60100000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW21_DVS = 0x60200000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW22_DVS = 0x60400000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW23_DVS = 0x60800000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VC_STBY = 0x61000000, ++ ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG0 = 0x68000001, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG1 = 0x68000002, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG2 = 0x68000004, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG3 = 0x68000008, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG4 = 0x68000010, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_EN = 0x68000020, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_MUX = 0x68000040, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN = 0x68000080, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX = 0x68000100, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX = 0x68000200, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2 = 0x68000400, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1 = 0x68000800, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A1ID_TX = 0x68001000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A1_CONFIG = 0x68002000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG = 0x68004000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A2_CONFIG = 0x68008000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR = 0x68080000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_STBY = 0x68100000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2 = 0x68200000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG_PRI_ADJ = 0x68400000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_TX_PRI_ADJ0 = 0x68800000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_TX_PRI_ADJ1 = 0x69000000, ++ ++ SSP_PCAP_ADJ_BIT_SYS_RST_CLR = 0x6c000001, ++ SSP_PCAP_ADJ_BIT_SYS_RST_MODE0 = 0x6c000002, ++ SSP_PCAP_ADJ_BIT_SYS_RST_MODE1 = 0x6c000004, ++ SSP_PCAP_ADJ_BIT_SYS_VFLASH_0 = 0x6c000008, ++ SSP_PCAP_ADJ_BIT_SYS_VFLASH_1 = 0x6c000010, ++ SSP_PCAP_ADJ_BIT_SYS_MID_SELECT = 0x6c000020, ++ SSP_PCAP_ADJ_BIT_SYS_MID_FET = 0x6c000040, ++ SSP_PCAP_ADJ_BIT_SYS_MAIN_LOW = 0x6c000080, ++ SSP_PCAP_ADJ_BIT_SYS_BATTFB_DIS = 0x6c000100, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG9 = 0x6c000200, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG10 = 0x6c000400, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG11 = 0x6c000800, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG12 = 0x6c001000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG13 = 0x6c002000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG14 = 0x6c004000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG15 = 0x6c008000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG16 = 0x6c010000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG17 = 0x6c020000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG18 = 0x6c040000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG19 = 0x6c080000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG20 = 0x6c100000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG21 = 0x6c200000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG22 = 0x6c400000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG23 = 0x6c800000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG24 = 0x6d000000 ++ ++}SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE; ++ ++/************************ FUNCTION PROTOTYPES **************************************/ ++extern void ssp_pcap_init(void); ++extern void ssp_pcap_release(void); ++ ++extern void ssp_pcap_open(SSP_PCAP_INIT_DRIVER_TYPE portType); ++extern void ssp_pcap_close(void); ++ ++extern void ssp_pcap_intoSleep_callBack(void); ++extern void ssp_pcap_wakeUp_callBack(void); ++ ++ ++extern SSP_PCAP_STATUS SSP_PCAP_write_data_to_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register,U32 ssp_pcap_register_value); ++extern SSP_PCAP_STATUS SSP_PCAP_read_data_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register,P_U32 p_ssp_pcap_register_value); ++ ++extern SSP_PCAP_STATUS SSP_PCAP_bit_set(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++extern SSP_PCAP_STATUS SSP_PCAP_bit_clean(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++extern SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++extern SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++extern U32 SSP_PCAP_get_register_value_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register ) ; ++ ++extern SSP_PCAP_STATUS SSP_PCAP_TSI_mode_set(TOUCH_SCREEN_DETECT_TYPE mode_Type ); ++extern SSP_PCAP_STATUS SSP_PCAP_TSI_start_XY_read(void); ++extern SSP_PCAP_STATUS SSP_PCAP_TSI_get_XY_value(P_U16 p_x,P_U16 p_y); ++extern SSP_PCAP_STATUS SSP_PCAP_CDC_CLK_set(PHONE_CDC_CLOCK_TYPE clkType); ++ ++extern SSP_PCAP_STATUS SSP_PCAP_CDC_SR_set(ST_SAMPLE_RATE_TYPE srType); ++extern SSP_PCAP_STATUS SSP_PCAP_BCLK_set(ST_BCLK_TIME_SLOT_TYPE bclkType); ++extern SSP_PCAP_STATUS SSP_PCAP_STCLK_set(ST_CLK_TYPE stClkType); ++extern SSP_PCAP_STATUS SSP_PCAP_DIG_AUD_FS_set(DIG_AUD_MODE_TYPE fsType); ++extern SSP_PCAP_STATUS SSP_PCAP_AUDIG_set(U32 audioInGain); ++extern SSP_PCAP_STATUS SSP_PCAP_MONO_set(MONO_TYPE monoType); ++extern SSP_PCAP_STATUS SSP_PCAP_AUDOG_set(U32 audioOutGain); ++ ++extern SSP_PCAP_STATUS SSP_PCAP_V_VIB_level_set(VibratorVoltageLevel_TYPE VIBLevelType); ++extern SSP_PCAP_STATUS SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_PORT_TYPE portType); ++extern SSP_PCAP_BIT_STATUS SSP_PCAP_get_audio_in_status(void); ++ ++/* for log */ ++extern void pcap_log_add_pure_data(u8* pData,u32 len); ++extern void pcap_log_add_data(u8* pData,u32 len); ++ ++/* screen lock on/off handler */ ++extern void ssp_pcap_screenlock_lock(u32 data); ++extern void ssp_pcap_screenlock_unlock(u32 data); ++ ++#endif +Index: linux-2.6.20.7/include/asm-arm/arch-pxa/irqs.h +=================================================================== +--- linux-2.6.20.7.orig/include/asm-arm/arch-pxa/irqs.h 2007-04-21 08:26:32.000000000 -0300 ++++ linux-2.6.20.7/include/asm-arm/arch-pxa/irqs.h 2007-04-21 08:26:37.000000000 -0300 +@@ -176,7 +176,8 @@ + #define NR_IRQS (IRQ_LOCOMO_SPI_TEND + 1) + #elif defined(CONFIG_ARCH_LUBBOCK) || \ + defined(CONFIG_MACH_LOGICPD_PXA270) || \ +- defined(CONFIG_MACH_MAINSTONE) ++ defined(CONFIG_MACH_MAINSTONE) || \ ++ defined(CONFIG_PXA_EZX) + #define NR_IRQS (IRQ_BOARD_END) + #else + #define NR_IRQS (IRQ_BOARD_START) +@@ -222,3 +223,16 @@ + #define IRQ_LOCOMO_GPIO_BASE (IRQ_BOARD_START + 1) + #define IRQ_LOCOMO_LT_BASE (IRQ_BOARD_START + 2) + #define IRQ_LOCOMO_SPI_BASE (IRQ_BOARD_START + 3) ++ ++/* EZX Interrupts (CONFIG_EZX) */ ++#define EZX_IRQ(x) (IRQ_BOARD_START + (x)) ++#define EZX_IRQ_ADCDONE EZX_IRQ(0) /* PCAP */ ++#define EZX_IRQ_TS EZX_IRQ(1) /* PCAP */ ++#define EZX_IRQ_USB4V EZX_IRQ(2) /* PCAP */ ++#define EZX_IRQ_USB1V EZX_IRQ(3) /* PCAP */ ++#define EZX_IRQ_HEADJACK EZX_IRQ(4) /* PCAP */ ++#define EZX_IRQ_MIC EZX_IRQ(5) /* PCAP */ ++#define EZX_IRQ_ADCDONE2 EZX_IRQ(6) /* PCAP */ ++#define EZX_IRQ_ONOFF EZX_IRQ(7) ++#define EZX_IRQ_ONOFF2 EZX_IRQ(8) ++ +Index: linux-2.6.20.7/arch/arm/mach-pxa/Makefile +=================================================================== +--- linux-2.6.20.7.orig/arch/arm/mach-pxa/Makefile 2007-04-21 08:26:37.000000000 -0300 ++++ linux-2.6.20.7/arch/arm/mach-pxa/Makefile 2007-04-21 08:45:09.000000000 -0300 +@@ -18,7 +18,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_PXA_EZX) += ezx.o ezx_lcd.o ezx_ssp.o ++obj-$(CONFIG_PXA_EZX) += ezx.o ezx_lcd.o ezx_ssp.o ezx-pcap.o + + # Support for blinky lights + led-y := leds.o +Index: linux-2.6.20.7/arch/arm/mach-pxa/ezx.c +=================================================================== +--- linux-2.6.20.7.orig/arch/arm/mach-pxa/ezx.c 2007-04-21 08:26:37.000000000 -0300 ++++ linux-2.6.20.7/arch/arm/mach-pxa/ezx.c 2007-04-21 08:51:15.000000000 -0300 +@@ -73,6 +73,24 @@ + .clk_pcap = 1, + }; + ++/* PCAP */ ++static struct resource ezxpcap_resources[] = { ++ [0] = { ++ .start = IRQ_GPIO1, ++ .end = IRQ_GPIO1, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++struct platform_device ezxpcap_device = { ++ .name = "ezx-pcap", ++ .id = -1, ++ .dev = { ++ .parent = &ezxssp_device.dev, ++ }, ++ .num_resources = ARRAY_SIZE(ezxpcap_resources), ++ .resource = ezxpcap_resources, ++}; + + /* OHCI Controller */ + +@@ -236,7 +254,7 @@ + }; + + +-static struct resource ezx_bp_resources[] = { ++static struct resource ezxbp_resources[] = { + [0] = { + .start = GPIO_BP_RDY, + .end = GPIO_BP_RDY, +@@ -256,15 +274,15 @@ + #endif + }; + +-static struct platform_device ezx_bp_device = { ++static struct platform_device ezxbp_device = { + .name = "ezx-bp", + .dev = { + //.parent = + //.platform_data = + }, + .id = -1, +- .num_resources = ARRAY_SIZE(ezx_bp_resources), +- .resource = ezx_bp_resources, ++ .num_resources = ARRAY_SIZE(ezxbp_resources), ++ .resource = ezxbp_resources, + }; + + static void __init ezx_init_gpio_irq(void) +@@ -297,7 +315,8 @@ + + static struct platform_device *devices[] __initdata = { + &ezxssp_device, +- &ezx_bp_device, ++ &ezxpcap_device, ++ &ezxbp_device, + }; + + static void __init a780_init(void) diff --git a/packages/linux/linux-ezx-2.6.20.7/ezx-serial-bug-workaround.patch b/packages/linux/linux-ezx-2.6.20.7/ezx-serial-bug-workaround.patch new file mode 100644 index 0000000000..9f30cc35fe --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/ezx-serial-bug-workaround.patch @@ -0,0 +1,45 @@ +Work around some errata in the pxa serial code (copied from motorolas 2.4.x tree) + +Index: linux-2.6.20.7/drivers/serial/pxa.c +=================================================================== +--- linux-2.6.20.7.orig/drivers/serial/pxa.c 2007-04-21 13:57:46.000000000 -0300 ++++ linux-2.6.20.7/drivers/serial/pxa.c 2007-04-21 14:05:03.000000000 -0300 +@@ -29,6 +29,10 @@ + #define SUPPORT_SYSRQ + #endif + ++#define pxa_buggy_port(x) ({ \ ++ int cpu_ver; asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver)); \ ++ ((x) == PORT_PXA && (cpu_ver & ~1) == 0x69052100); }) ++ + #include <linux/module.h> + #include <linux/ioport.h> + #include <linux/init.h> +@@ -195,7 +199,7 @@ + if (uart_circ_empty(xmit)) + serial_pxa_stop_tx(&up->port); + } +- ++static inline irqreturn_t serial_pxa_irq(int, void *); + static void serial_pxa_start_tx(struct uart_port *port) + { + struct uart_pxa_port *up = (struct uart_pxa_port *)port; +@@ -203,6 +207,8 @@ + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_out(up, UART_IER, up->ier); ++ if (pxa_buggy_port(up->port.type)) ++ serial_pxa_irq(up->port.irq, NULL); + } + } + +@@ -298,6 +304,9 @@ + + mcr |= up->mcr; + ++ if (pxa_buggy_port(up->port.type) && up->port.irq != 0) ++ mcr ^= UART_MCR_OUT2; ++ + serial_out(up, UART_MCR, mcr); + } + diff --git a/packages/linux/linux-ezx-2.6.20.7/mux-fix-init-errorpath.patch b/packages/linux/linux-ezx-2.6.20.7/mux-fix-init-errorpath.patch new file mode 100644 index 0000000000..716ef86fd1 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/mux-fix-init-errorpath.patch @@ -0,0 +1,20 @@ +Index: linux-2.6.16/drivers/char/ts0710_mux_usb.c +=================================================================== +--- linux-2.6.16.orig/drivers/char/ts0710_mux_usb.c 2007-01-17 00:10:32.000000000 +0100 ++++ linux-2.6.16/drivers/char/ts0710_mux_usb.c 2007-01-17 00:42:23.000000000 +0100 +@@ -811,7 +811,6 @@ + /*init the related mux interface*/ + if (!(bvd_ipc = kzalloc(sizeof(struct ipc_usb_data), GFP_KERNEL))) { + err("usb_ipc_init: Out of memory."); +- usb_deregister(&usb_ipc_driver); + return -ENOMEM; + } + bvd_dbg("usb_ipc_init: Address of bvd_ipc:%p", bvd_ipc); +@@ -819,7 +818,6 @@ + if (!(bvd_ipc->xmit.buf = kmalloc(IPC_USB_XMIT_SIZE, GFP_KERNEL))) { + err("usb_ipc_init: Not enough memory for the input buffer."); + kfree(bvd_ipc); +- usb_deregister(&usb_ipc_driver); + return -ENOMEM; + } + bvd_dbg("usb_ipc_init: bvd_ipc->xmit.buf address:%p", diff --git a/packages/linux/linux-ezx-2.6.20.7/mux-fix-makefile.patch b/packages/linux/linux-ezx-2.6.20.7/mux-fix-makefile.patch new file mode 100644 index 0000000000..f7884ca524 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/mux-fix-makefile.patch @@ -0,0 +1,14 @@ +Index: linux-2.6.20.7/drivers/char/Makefile +=================================================================== +--- linux-2.6.20.7.orig/drivers/char/Makefile 2007-04-22 10:51:23.000000000 +0200 ++++ linux-2.6.20.7/drivers/char/Makefile 2007-04-22 10:52:48.000000000 +0200 +@@ -101,7 +101,8 @@ + obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o + obj-$(CONFIG_TCG_TPM) += tpm/ + +-obj-$(CONFIG_TS0710_MUX) += ts0710_mux.o ts0710_mux_usb.o ++obj-$(CONFIG_TS0710_MUX_USB) += ts0710_mux_usb.o ++obj-$(CONFIG_TS0710_MUX) += ts0710_mux.o + + + # Files generated that shall be removed upon make clean diff --git a/packages/linux/linux-ezx-2.6.20.7/mux-fix-tty-driver.patch b/packages/linux/linux-ezx-2.6.20.7/mux-fix-tty-driver.patch new file mode 100644 index 0000000000..2e1aabd952 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/mux-fix-tty-driver.patch @@ -0,0 +1,125 @@ +Index: linux-2.6.20.7/drivers/char/ts0710_mux.c +=================================================================== +--- linux-2.6.20.7.orig/drivers/char/ts0710_mux.c 2007-04-22 10:51:31.000000000 +0200 ++++ linux-2.6.20.7/drivers/char/ts0710_mux.c 2007-04-22 10:53:05.000000000 +0200 +@@ -241,7 +241,8 @@ + static volatile __u8 mux_recv_info_flags[NR_MUXS]; + static mux_recv_struct *mux_recv_queue = NULL; + +-static struct tty_driver mux_driver; ++// Local for 2.6? ++static struct tty_driver *mux_driver; + + #ifdef USB_FOR_MUX + #define COMM_FOR_MUX_DRIVER usb_for_mux_driver +@@ -3007,6 +3008,7 @@ + #else + mux_tty[line]++; + dlci = tty2dlci[line]; ++ mux_table[line] = tty; + + /* if( dlci == 1 ) { */ + /* Open server channel 0 first */ +@@ -3087,6 +3089,7 @@ + } + } + ++ + retval = 0; + #endif + out: +@@ -3894,43 +3897,50 @@ + INIT_WORK(&receive_tqueue, receive_worker, NULL); + INIT_WORK(&post_recv_tqueue, post_recv_worker, NULL); + +- memset(&mux_driver, 0, sizeof(struct tty_driver)); +- memset(&mux_tty, 0, sizeof(mux_tty)); +- mux_driver.magic = TTY_DRIVER_MAGIC; +- mux_driver.driver_name = "ts0710mux"; +- mux_driver.name = "ts0710mux"; +- mux_driver.major = TS0710MUX_MAJOR; +- mux_driver.minor_start = TS0710MUX_MINOR_START; +- mux_driver.num = NR_MUXS; +- mux_driver.type = TTY_DRIVER_TYPE_SERIAL; +- mux_driver.subtype = SERIAL_TYPE_NORMAL; +- mux_driver.init_termios = tty_std_termios; +- mux_driver.init_termios.c_iflag = 0; +- mux_driver.init_termios.c_oflag = 0; +- mux_driver.init_termios.c_cflag = B38400 | CS8 | CREAD; +- mux_driver.init_termios.c_lflag = 0; +- mux_driver.flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW; +- +- mux_driver.ttys = mux_table; +- mux_driver.termios = mux_termios; +- mux_driver.termios_locked = mux_termios_locked; ++ mux_driver = alloc_tty_driver(NR_MUXS); ++ if (!mux_driver) ++ return -ENOMEM; ++ ++ mux_driver->owner = THIS_MODULE; ++ mux_driver->driver_name = "ts0710mux"; ++ mux_driver->name = "mux"; ++ mux_driver->devfs_name = "mux"; ++ mux_driver->major = TS0710MUX_MAJOR; ++ mux_driver->minor_start = TS0710MUX_MINOR_START; ++ mux_driver->type = TTY_DRIVER_TYPE_SERIAL; ++ mux_driver->subtype = SERIAL_TYPE_NORMAL; ++ mux_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW; ++ ++ mux_driver->init_termios = tty_std_termios; ++ mux_driver->init_termios.c_iflag = 0; ++ mux_driver->init_termios.c_oflag = 0; ++ mux_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; ++ mux_driver->init_termios.c_lflag = 0; ++ ++// mux_driver.ttys = mux_table; ++ mux_driver->termios = mux_termios; ++ mux_driver->termios_locked = mux_termios_locked; + // mux_driver.driver_state = mux_state; +- mux_driver.other = NULL; ++ mux_driver->other = NULL; + +- mux_driver.open = mux_open; +- mux_driver.close = mux_close; +- mux_driver.write = mux_write; +- mux_driver.write_room = mux_write_room; +- mux_driver.flush_buffer = mux_flush_buffer; +- mux_driver.chars_in_buffer = mux_chars_in_buffer; +- mux_driver.throttle = mux_throttle; +- mux_driver.unthrottle = mux_unthrottle; +- mux_driver.ioctl = mux_ioctl; +- mux_driver.owner = THIS_MODULE; ++ mux_driver->open = mux_open; ++ mux_driver->close = mux_close; ++ mux_driver->write = mux_write; ++ mux_driver->write_room = mux_write_room; ++ mux_driver->flush_buffer = mux_flush_buffer; ++ mux_driver->chars_in_buffer = mux_chars_in_buffer; ++ mux_driver->throttle = mux_throttle; ++ mux_driver->unthrottle = mux_unthrottle; ++ mux_driver->ioctl = mux_ioctl; + +- if (tty_register_driver(&mux_driver)) ++ // FIXME: No panic() here ++ if (tty_register_driver(mux_driver)) + panic("Couldn't register mux driver"); + ++ for (j=0; j<NR_MUXS; j++) ++ tty_register_device(mux_driver, j, NULL); ++ ++ + COMM_MUX_DISPATCHER = mux_dispatcher; + COMM_MUX_SENDER = mux_sender; + +@@ -3964,7 +3974,10 @@ + mux_recv_info[j] = 0; + } + +- if (tty_unregister_driver(&mux_driver)) ++ for (j=0; j<NR_MUXS; j++) ++ tty_unregister_device(mux_driver, j); ++ ++ if (tty_unregister_driver(mux_driver)) + panic("Couldn't unregister mux driver"); + } + diff --git a/packages/linux/linux-ezx-2.6.20.7/mux-fix.patch b/packages/linux/linux-ezx-2.6.20.7/mux-fix.patch new file mode 100644 index 0000000000..b820762f41 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/mux-fix.patch @@ -0,0 +1,164 @@ +Index: linux-2.6.20.7/drivers/char/ts0710_mux_usb.c +=================================================================== +--- linux-2.6.20.7.orig/drivers/char/ts0710_mux_usb.c 2007-04-21 18:07:45.000000000 +0200 ++++ linux-2.6.20.7/drivers/char/ts0710_mux_usb.c 2007-04-21 20:55:13.000000000 +0200 +@@ -626,7 +626,6 @@ + } + + interface = &intf->cur_altsetting->desc; +- endpoint = &intf->cur_altsetting->endpoint[0].desc; + /* Start checking for two bulk endpoints or ... FIXME: This is a future + * enhancement...*/ + bvd_dbg("usb_ipc_probe: Number of Endpoints:%d", +@@ -638,30 +637,26 @@ + + ep_cnt = have_bulk_in_mux = have_bulk_out_mux = 0; + +- bvd_dbg("usb_ipc_probe: endpoint[0] is:%x", +- (&endpoint[0])->bEndpointAddress); +- bvd_dbg("usb_ipc_probe: endpoint[1] is:%x ", +- (&endpoint[1])->bEndpointAddress); +- + while (ep_cnt < interface->bNumEndpoints) { +- +- if (!have_bulk_in_mux && IS_EP_BULK_IN(endpoint[ep_cnt])) { +- bvd_dbg("usb_ipc_probe: bEndpointAddress(IN) is:%x ", +- (&endpoint[ep_cnt])->bEndpointAddress); +- have_bulk_in_mux = +- (&endpoint[ep_cnt])->bEndpointAddress; +- readsize = (&endpoint[ep_cnt])->wMaxPacketSize; ++ endpoint = &intf->cur_altsetting->endpoint[ep_cnt].desc; ++ bvd_dbg("usb_ipc_probe: endpoint[%i] is: %x", ep_cnt, ++ endpoint->bEndpointAddress); ++ ++ if (!have_bulk_in_mux && IS_EP_BULK_IN(*endpoint)) { ++ bvd_dbg("usb_ipc_probe: bEndpointAddress(IN) is: %x ", ++ endpoint->bEndpointAddress); ++ have_bulk_in_mux = endpoint->bEndpointAddress; ++ readsize = endpoint->wMaxPacketSize; + bvd_dbg("usb_ipc_probe: readsize=%d", readsize); + ep_cnt++; + continue; + } + +- if (!have_bulk_out_mux && IS_EP_BULK_OUT(endpoint[ep_cnt])) { +- bvd_dbg("usb_ipc_probe: bEndpointAddress(OUT) is:%x ", +- (&endpoint[ep_cnt])->bEndpointAddress); +- have_bulk_out_mux = +- (&endpoint[ep_cnt])->bEndpointAddress; +- writesize = (&endpoint[ep_cnt])->wMaxPacketSize; ++ if (!have_bulk_out_mux && IS_EP_BULK_OUT(*endpoint)) { ++ bvd_dbg("usb_ipc_probe: bEndpointAddress(OUT) is: %x ", ++ endpoint->bEndpointAddress); ++ have_bulk_out_mux = endpoint->bEndpointAddress; ++ writesize = endpoint->wMaxPacketSize; + bvd_dbg("usb_ipc_probe: writesize=%d", writesize); + ep_cnt++; + continue; +@@ -718,21 +713,27 @@ + bvd_ipc->bh_bp.func = usbipc_bh_bp_func; + bvd_ipc->bh_bp.data = (unsigned long) bvd_ipc; + ++ bvd_dbg("after assignements"); + /*Build a write urb*/ ++ usb_init_urb(&bvd_ipc->writeurb_mux); + usb_fill_bulk_urb(&bvd_ipc->writeurb_mux, usbdev, + usb_sndbulkpipe(bvd_ipc->ipc_dev, + bvd_ipc->bulk_out_ep_mux), + bvd_ipc->obuf, writesize, usb_ipc_write_bulk, + bvd_ipc); + //bvd_ipc->writeurb_mux.transfer_flags |= USB_ASYNC_UNLINK; ++ bvd_dbg("after write urb"); + + /*Build a read urb and send a IN token first time*/ ++ usb_init_urb(&bvd_ipc->readurb_mux); + usb_fill_bulk_urb(&bvd_ipc->readurb_mux, usbdev, + usb_rcvbulkpipe(usbdev, bvd_ipc->bulk_in_ep_mux), + bvd_ipc->ibuf, readsize, usb_ipc_read_bulk, bvd_ipc); + //bvd_ipc->readurb_mux.transfer_flags |= USB_ASYNC_UNLINK; ++ bvd_dbg("after read urb"); + +- usb_driver_claim_interface(&usb_ipc_driver, intf, bvd_ipc); ++ //usb_driver_claim_interface(&usb_ipc_driver, intf, bvd_ipc); ++ bvd_dbg("after claim interface"); + //usb_driver_claim_interface(&usb_ipc_driver, &ipccfg->interface[1], bvd_ipc); + + // a2590c: dsplog is not supported by this driver +@@ -740,6 +741,8 @@ + // &ipccfg->interface[2], bvd_ipc); + /*send a IN token first time*/ + bvd_ipc->readurb_mux.dev = bvd_ipc->ipc_dev; ++ bvd_dbg("after assignement"); ++ + if (usb_submit_urb(&bvd_ipc->readurb_mux, GFP_ATOMIC)) + printk("usb_ipc_prob: usb_submit_urb(read mux bulk) failed!\n"); + +@@ -750,7 +753,7 @@ + tasklet_schedule(&bvd_ipc->bh); + } + +- printk("usb_ipc_probe: completed probe!"); ++ printk("usb_ipc_probe: completed probe!\n"); + usb_set_intfdata(intf, &bvd_ipc); + return 0; + } +@@ -760,21 +763,23 @@ + //struct usb_device *usbdev = interface_to_usbdev(intf); + struct ipc_usb_data *bvd_ipc_disconnect = usb_get_intfdata(intf); + +- printk("usb_ipc_disconnect:*** \n"); + ++ printk("usb_ipc_disconnect. bvd_ipc_disconnect address: %p\n", bvd_ipc_disconnect); ++ ++ //FIXME: Memory leak? + if ((UHCRHPS3 & 0x4) == 0) +- usb_unlink_urb(&bvd_ipc_disconnect->readurb_mux); ++ // usb_unlink_urb(&bvd_ipc_disconnect->readurb_mux); + +- usb_unlink_urb(&bvd_ipc_disconnect->writeurb_mux); ++ //usb_unlink_urb(&bvd_ipc_disconnect->writeurb_mux); + + bvd_ipc_disconnect->ipc_flag = IPC_USB_PROBE_NOT_READY; + kfree(bvd_ipc_disconnect->ibuf); + kfree(bvd_ipc_disconnect->obuf); + +- usb_driver_release_interface(&usb_ipc_driver, +- bvd_ipc_disconnect->ipc_dev->actconfig->interface[0]); +- usb_driver_release_interface(&usb_ipc_driver, +- bvd_ipc_disconnect->ipc_dev->actconfig->interface[1]); ++ //usb_driver_release_interface(&usb_ipc_driver, ++ // bvd_ipc_disconnect->ipc_dev->actconfig->interface[0]); ++ //usb_driver_release_interface(&usb_ipc_driver, ++ // bvd_ipc_disconnect->ipc_dev->actconfig->interface[1]); + + //a2590c: dsplog interface is not supported by this driver + //usb_driver_release_interface(&usb_ipc_driver, &bvd_ipc_disconnect->ipc_dev->actconfig->interface[2]); +@@ -803,13 +808,6 @@ + int result; + + bvd_dbg("init usb_ipc"); +- /* register driver at the USB subsystem */ +- result = usb_register(&usb_ipc_driver); +- if (result < 0) { +- err ("usb ipc driver could not be registered"); +- return result; +- } +- + /*init the related mux interface*/ + if (!(bvd_ipc = kzalloc(sizeof(struct ipc_usb_data), GFP_KERNEL))) { + err("usb_ipc_init: Out of memory."); +@@ -836,6 +834,14 @@ + usb_for_mux_driver = &ipcusb_tty_driver; + usb_for_mux_tty = &ipcusb_tty; + ++ /* register driver at the USB subsystem */ ++ // this was called before bvd_ipc was allocated ++ result = usb_register(&usb_ipc_driver); ++ if (result < 0) { ++ err ("usb ipc driver could not be registered"); ++ return result; ++ } ++ + /* init timers for ipcusb read process and usb suspend */ + init_timer(&ipcusb_timer); + ipcusb_timer.function = ipcusb_timeout; diff --git a/packages/linux/linux-ezx-2.6.20.7/mux-ifdef-ezx-features.patch b/packages/linux/linux-ezx-2.6.20.7/mux-ifdef-ezx-features.patch new file mode 100644 index 0000000000..f9ad633c76 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/mux-ifdef-ezx-features.patch @@ -0,0 +1,85 @@ +diff -pruN linux-2.6.20.7/drivers/char/ts0710_mux_usb.c linux-2.6.20.7_x386/drivers/char/ts0710_mux_usb.c +--- linux-2.6.20.7/drivers/char/ts0710_mux_usb.c 2007-04-22 10:51:38.000000000 +0200 ++++ linux-2.6.20.7_x386/drivers/char/ts0710_mux_usb.c 2007-04-22 11:44:54.000000000 +0200 +@@ -35,10 +35,14 @@ + #include <linux/list.h> + #include <linux/errno.h> + #include <asm/uaccess.h> ++ ++#ifdef CONFIG_PXA_EZX + #include <asm/hardware.h> + #include <asm/arch/hardware.h> + #include <asm/arch-pxa/pxa-regs.h> + #include <asm/arch-pxa/ezx.h> ++#endif ++ + #include <linux/slab.h> + #include <linux/miscdevice.h> + #include <linux/init.h> +@@ -341,8 +345,10 @@ static void usb_ipc_write_bulk(struct ur + + static void wakeup_timeout(unsigned long data) + { ++#ifdef CONFIG_PXA_EZX + GPSR(GPIO_MCU_INT_SW) = GPIO_bit(GPIO_MCU_INT_SW); + bvd_dbg("wakup_timeout: send GPIO_MCU_INT_SW signal!"); ++#endif + } + + static void suspend_timeout(unsigned long data) +@@ -353,10 +359,12 @@ static void suspend_timeout(unsigned lon + bvd_dbg("suspend_timeout: add the suspend timer again"); + } else { + unlink_urbs(&bvd_ipc->readurb_mux); ++#ifdef CONFIG_PXA_EZX + UHCRHPS3 = 0x4; + mdelay(40); + bvd_dbg("suspend_timeout: send SUSPEND signal! UHCRHPS3=0x%x", + UHCRHPS3); ++#endif + } + } + +@@ -404,6 +412,7 @@ static void ipcusb_xmit_data(void) + bvd_ipc->writeurb_mux.transfer_buffer_length = buf_num; + bvd_dbg("ipcusb_xmit_data: copy data to write urb finished! "); + ++#ifdef CONFIG_PXA_EZX + if ((UHCRHPS3 & 0x4) == 0x4) { + static int ret; + int time = 0; +@@ -442,6 +451,7 @@ static void ipcusb_xmit_data(void) + "failed! status=%d\n", ret); + bvd_dbg("ipcusb_xmit_data: Send a IN token successfully!"); + } ++#endif + + sumbit_times++; + bvd_ipc->write_finished_flag = 0; +@@ -464,12 +474,16 @@ static void usbipc_bh_func(unsigned long + + static void usbipc_bh_bp_func(unsigned long param) + { ++#ifdef CONFIG_PXA_EZX + if ((UHCRHPS3 & 0x4) == 0x4) { + UHCRHPS3 = 0x8; ++#endif + mdelay(40); ++#ifdef CONFIG_PXA_EZX + bvd_dbg("ipcusb_softint_send_readurb: Send RESUME signal! " + "UHCRHPS3=0x%x", UHCRHPS3); + } ++#endif + if (bvd_ipc->ipc_flag == IPC_USB_PROBE_READY) { + //get_halted_bit(); + +@@ -734,7 +748,9 @@ static void usb_ipc_disconnect(struct us + printk("usb_ipc_disconnect. bvd_ipc_disconnect address: %p\n", bvd_ipc_disconnect); + + //FIXME: Memory leak? ++#ifdef CONFIG_PXA_EZX + if ((UHCRHPS3 & 0x4) == 0) ++#endif + // usb_unlink_urb(&bvd_ipc_disconnect->readurb_mux); + + //usb_unlink_urb(&bvd_ipc_disconnect->writeurb_mux); diff --git a/packages/linux/linux-ezx-2.6.20.7/mux-linux-2.6.20.7-fix.patch b/packages/linux/linux-ezx-2.6.20.7/mux-linux-2.6.20.7-fix.patch new file mode 100644 index 0000000000..bc6e3972b6 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/mux-linux-2.6.20.7-fix.patch @@ -0,0 +1,96 @@ +diff -pruN linux-2.6.20.7/drivers/char/ts0710.h linux-2.6.20.7_x386/drivers/char/ts0710.h +--- linux-2.6.20.7/drivers/char/ts0710.h 2007-04-22 10:51:23.000000000 +0200 ++++ linux-2.6.20.7_x386/drivers/char/ts0710.h 2007-04-22 11:16:37.000000000 +0200 +@@ -45,7 +45,7 @@ + * 11/18/2002 Modified + */ + +-#include <linux/config.h> ++//#include <linux/config.h> + #include <linux/module.h> + + #include <linux/errno.h> +@@ -58,7 +58,7 @@ + #include <linux/major.h> + #include <linux/mm.h> + #include <linux/init.h> +-#include <linux/devfs_fs_kernel.h> ++//#include <linux/devfs_fs_kernel.h> + + #include <asm/uaccess.h> + #include <asm/system.h> +diff -pruN linux-2.6.20.7/drivers/char/ts0710_mux.c linux-2.6.20.7_x386/drivers/char/ts0710_mux.c +--- linux-2.6.20.7/drivers/char/ts0710_mux.c 2007-04-22 10:53:05.000000000 +0200 ++++ linux-2.6.20.7_x386/drivers/char/ts0710_mux.c 2007-04-22 11:20:07.000000000 +0200 +@@ -46,7 +46,7 @@ + * 11/18/2002 Second version + * 04/21/2004 Add GPRS PROC + */ +-#include <linux/config.h> ++//#include <linux/config.h> + #include <linux/module.h> + #include <linux/types.h> + +@@ -70,7 +70,7 @@ + #include <linux/mm.h> + #include <linux/slab.h> + #include <linux/init.h> +-#include <linux/devfs_fs_kernel.h> ++//#include <linux/devfs_fs_kernel.h> + //#include <syslog.h> + + #include <asm/uaccess.h> +@@ -1894,11 +1894,14 @@ int ts0710_recv_data(ts0710_con * ts0710 + if (test_bit(TTY_THROTTLED, &tty->flags)) { + queue_data = 1; + } else { ++ /* + if (test_bit + (TTY_DONT_FLIP, &tty->flags)) { + queue_data = 1; + post_recv = 1; +- } else if (recv_info->total) { ++ } else ++ */ ++ if (recv_info->total) { + queue_data = 1; + post_recv = 1; + } else if (recv_room < uih_len) { +@@ -3499,11 +3502,14 @@ static void post_recv_worker(void *priva + if (test_bit(TTY_THROTTLED, &tty->flags)) { + add_post_recv_queue(&post_recv_q, recv_info); + continue; +- } else if (test_bit(TTY_DONT_FLIP, &tty->flags)) { ++ } ++ /* ++ else if (test_bit(TTY_DONT_FLIP, &tty->flags)) { + post_recv = 1; + add_post_recv_queue(&post_recv_q, recv_info); + continue; + } ++ */ + + flow_control = 0; + recv_packet2 = recv_info->mux_packet; +@@ -3893,9 +3899,9 @@ static int __init mux_init(void) + } + post_recv_count_flag = 0; + +- INIT_WORK(&send_tqueue, send_worker, NULL); +- INIT_WORK(&receive_tqueue, receive_worker, NULL); +- INIT_WORK(&post_recv_tqueue, post_recv_worker, NULL); ++ INIT_WORK(&send_tqueue, send_worker); ++ INIT_WORK(&receive_tqueue, receive_worker); ++ INIT_WORK(&post_recv_tqueue, post_recv_worker); + + mux_driver = alloc_tty_driver(NR_MUXS); + if (!mux_driver) +@@ -3904,7 +3910,7 @@ static int __init mux_init(void) + mux_driver->owner = THIS_MODULE; + mux_driver->driver_name = "ts0710mux"; + mux_driver->name = "mux"; +- mux_driver->devfs_name = "mux"; ++ //mux_driver->devfs_name = "mux"; + mux_driver->major = TS0710MUX_MAJOR; + mux_driver->minor_start = TS0710MUX_MINOR_START; + mux_driver->type = TTY_DRIVER_TYPE_SERIAL; diff --git a/packages/linux/linux-ezx-2.6.20.7/mux-remove-flipbuffers.patch b/packages/linux/linux-ezx-2.6.20.7/mux-remove-flipbuffers.patch new file mode 100644 index 0000000000..d4781f9fc7 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/mux-remove-flipbuffers.patch @@ -0,0 +1,269 @@ +Index: linux-2.6.16/drivers/char/ts0710_mux_usb.c +=================================================================== +--- linux-2.6.16.orig/drivers/char/ts0710_mux_usb.c 2007-01-17 00:52:25.000000000 +0100 ++++ linux-2.6.16/drivers/char/ts0710_mux_usb.c 2007-01-17 00:52:26.000000000 +0100 +@@ -133,6 +133,7 @@ + + struct circ_buf xmit; /* write cric bufffer */ + struct list_head in_buf_list; ++ spinlock_t in_buf_lock; + char bulk_in_ep_mux, + bulk_out_ep_mux, + bulk_in_ep_dsplog; +@@ -204,9 +205,39 @@ + return; + } + memcpy(inbuf->body, (unsigned char*)urb->transfer_buffer, count); ++ spin_lock(&bvd_ipc->in_buf_lock); + list_add_tail(&inbuf->list, &bvd_ipc->in_buf_list); ++ spin_unlock(&bvd_ipc->in_buf_lock); + } + ++int get_from_inbuf_list(const unsigned char *buf, int dst_count) ++{ ++ int ret = 0; ++ spin_lock(&bvd_ipc->in_buf_lock); ++ if (!(list_empty(&bvd_ipc->in_buf_list))) { ++ int src_count; ++ buf_list_t *inbuf; ++ struct list_head *ptr; ++ ++ ptr = bvd_ipc->in_buf_list.next; ++ inbuf = list_entry(ptr, buf_list_t, list); ++ src_count = inbuf->size; ++ if (dst_count >= src_count) { ++ memcpy(buf, inbuf->body, src_count); ++ ret = src_count; ++ list_del(ptr); ++ kfree(inbuf->body); ++ kfree(inbuf); ++ } else { ++ bvd_dbg("get_from_inbuf_list: not enough space in destination buffer"); ++ } ++ } ++ spin_unlock(&bvd_ipc->in_buf_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL(get_from_inbuf_list); ++ + static void ipcusb_timeout(unsigned long data) + { + struct tty_struct *tty = &ipcusb_tty; +@@ -214,13 +245,14 @@ + + bvd_dbg("ipcusb_timeout***"); + ++ spin_lock(&bvd_ipc->in_buf_lock); + while (!(list_empty(&bvd_ipc->in_buf_list))) { + int count; + buf_list_t *inbuf; + struct list_head *ptr = NULL; + + ptr = bvd_ipc->in_buf_list.next; +- inbuf = list_entry (ptr, buf_list_t, list); ++ inbuf = list_entry(ptr, buf_list_t, list); + count = inbuf->size; + if (tty_insert_flip_string(tty, inbuf->body, count) >= count) { + list_del(ptr); +@@ -232,10 +264,12 @@ + break; + } + } ++ spin_unlock(&bvd_ipc->in_buf_lock); + + if (usb_mux_dispatcher) + usb_mux_dispatcher(tty); /**call Liu changhui's func.**/ + ++ spin_lock(&bvd_ipc->in_buf_lock); + if (list_empty(&bvd_ipc->in_buf_list)) { + urb->actual_length = 0; + urb->dev = bvd_ipc->ipc_dev; +@@ -246,6 +280,7 @@ + ipcusb_timer.data = (unsigned long)urb; + mod_timer(&ipcusb_timer, jiffies+(10*HZ/1000)); + } ++ spin_unlock(&bvd_ipc->in_buf_lock); + } + + static void usb_ipc_read_bulk(struct urb *urb, struct pt_regs *regs) +@@ -266,69 +301,11 @@ + if (count > 0 && ((*ipcusb_bp_to_ap) != NULL)) + (*ipcusb_bp_to_ap)(urb->transfer_buffer, urb->actual_length); + +- if (!(list_empty(&bvd_ipc->in_buf_list))) { +- int need_mux = 0; +- +- bvd_dbg("usb_ipc_read_bulk: some urbs in_buf_list"); +- if (count > 0) { +- bvd_ipc->suspend_flag = 1; +- append_to_inbuf_list(urb); /* append the current received urb */ +-#if 0 +- if(jiffies - last_jiff > ICL_EVENT_INTERVAL) +- { +- last_jiff = jiffies; +- queue_apm_event(KRNL_ICL, NULL); +- } +-#endif +- } +- +- while (!(list_empty(&bvd_ipc->in_buf_list))) { +- struct list_head* ptr = NULL; +- ptr = bvd_ipc->in_buf_list.next; +- inbuf = list_entry(ptr, buf_list_t, list); +- count = inbuf->size; +- need_mux = 1; +- +- tty_insert_flip_string(tty, inbuf->body, count); +- +- list_del(ptr); +- kfree(inbuf->body); +- inbuf->body = NULL; +- kfree(inbuf); +- } +- +- if (usb_mux_dispatcher && need_mux) +- usb_mux_dispatcher(tty); /* call Liu changhui's func. */ +- +- if (list_empty(&bvd_ipc->in_buf_list)) { +- urb->actual_length = 0; +- urb->dev = bvd_ipc->ipc_dev; +- if (usb_submit_urb(urb, GFP_ATOMIC)) +- bvd_dbg("usb_ipc_read_bulk: " +- "failed resubmitting read urb"); +- bvd_dbg("usb_ipc_read_bulk: resubmited read urb"); +- } else { +- ipcusb_timer.data = (unsigned long)urb; +- mod_timer(&ipcusb_timer, jiffies+(10*HZ/1000)); +- } +- } else if (count > 0) { +- bvd_dbg("usb_ipc_read_bulk: no urbs in_buf_list"); ++ if (count > 0) { ++ bvd_dbg("usb_ipc_read_bulk: inserting buffer into in_buf_list"); + bvd_ipc->suspend_flag = 1; + +- if (tty_insert_flip_string(tty, urb->transfer_buffer, +- count) < count) { +- bvd_ipc->suspend_flag = 1; +- append_to_inbuf_list(urb); +- ipcusb_timer.data = (unsigned long)urb; +- mod_timer(&ipcusb_timer, jiffies+(10*HZ/1000)); +-#if 0 +- if(jiffies - last_jiff > ICL_EVENT_INTERVAL) +- { +- last_jiff = jiffies; +- queue_apm_event(KRNL_ICL, NULL); +- } +-#endif +- } ++ append_to_inbuf_list(urb); + + if (usb_mux_dispatcher) + usb_mux_dispatcher(tty); /* call Liu changhui's func. */ +@@ -337,13 +314,6 @@ + urb->dev = bvd_ipc->ipc_dev; + if (usb_submit_urb(urb, GFP_ATOMIC)) + bvd_dbg("failed resubmitting read urb"); +-#if 0 +- if(jiffies - last_jiff > ICL_EVENT_INTERVAL) +- { +- last_jiff = jiffies; +- queue_apm_event(KRNL_ICL, NULL); +- } +-#endif + bvd_dbg("usb_ipc_read_bulk: resubmited read urb"); + } + +@@ -705,7 +675,8 @@ + bvd_ipc->bulk_out_ep_mux= have_bulk_out_mux; + bvd_ipc->ipc_dev = usbdev; + bvd_ipc->writesize = writesize; +- INIT_LIST_HEAD (&bvd_ipc->in_buf_list); ++ INIT_LIST_HEAD(&bvd_ipc->in_buf_list); ++ bvd_ipc->in_buf_lock = SPIN_LOCK_UNLOCKED; + + bvd_ipc->bh.func = usbipc_bh_func; + bvd_ipc->bh.data = (unsigned long) bvd_ipc; +Index: linux-2.6.16/drivers/char/ts0710_mux.c +=================================================================== +--- linux-2.6.16.orig/drivers/char/ts0710_mux.c 2007-01-17 00:52:23.000000000 +0100 ++++ linux-2.6.16/drivers/char/ts0710_mux.c 2007-01-17 00:52:26.000000000 +0100 +@@ -3149,7 +3149,7 @@ + static void receive_worker(void *private_) + { + struct tty_struct *tty = COMM_FOR_MUX_TTY; +- int i, count; ++ int i, count, tbuf_free, tbuf_read; + static unsigned char tbuf[TS0710MUX_MAX_BUF_SIZE]; + static unsigned char *tbuf_ptr = &tbuf[0]; + static unsigned char *start_flag = 0; +@@ -3167,29 +3167,39 @@ + + UNUSED_PARAM(private_); + +- if (!tty) +- return; ++ if (!tty) ++ return; ++ ++ while (1) { ++ tbuf_free = TS0710MUX_MAX_BUF_SIZE - (tbuf_ptr - tbuf); ++ TS0710_PRINTK("Reading max %i bytes from ts0710_mux_usb inbuf.\n", tbuf_free); ++ tbuf_read = get_from_inbuf_list(tbuf_ptr, tbuf_free); ++ if (tbuf_read == 0) { ++ break; ++ } else { ++ TS0710_PRINTK("Read %i bytes.\n", tbuf_read); ++ }; ++ tbuf_ptr += tbuf_read; ++ }; ++ ++ count = (tbuf_ptr - tbuf); ++ ++ // Should be impossible? ++ //if (count > (TS0710MUX_MAX_BUF_SIZE - (tbuf_ptr - tbuf))) { ++ // TS0710_PRINTK ++ // ("MUX receive_worker: !!!!! Exceed buffer boundary !!!!!\n"); ++ // count = (TS0710MUX_MAX_BUF_SIZE - (tbuf_ptr - tbuf)); ++ //} + + #ifdef USB_FOR_MUX +- TS0710_DEBUG("Receive following bytes from IPC-USB"); ++ TS0710_DEBUG("Received following bytes from IPC-USB"); + #else +- TS0710_DEBUG("Receive following bytes from UART"); ++ TS0710_DEBUG("Received following bytes from UART"); + #endif +- +- TS0710_DEBUGHEX(cp, count); +- +- if (count > (TS0710MUX_MAX_BUF_SIZE - (tbuf_ptr - tbuf))) { +- TS0710_PRINTK +- ("MUX receive_worker: !!!!! Exceed buffer boundary !!!!!\n"); +- count = (TS0710MUX_MAX_BUF_SIZE - (tbuf_ptr - tbuf)); +- } +- +- count = tty_buffer_request_room(tty, count); +- +- for (i = 0; i < count; i++) +- tty_insert_flip_char(tty, tbuf_ptr[i], TTY_NORMAL); +- +- tbuf_ptr += count; ++ TS0710_DEBUGHEX(tbuf, count); ++ ++ //gets updated above ++ //tbuf_ptr += count; + search = &tbuf[0]; + + if (test_and_set_bit(RECV_RUNNING, &mux_recv_flags)) { +Index: linux-2.6.16/drivers/char/ts0710_mux_usb.h +=================================================================== +--- linux-2.6.16.orig/drivers/char/ts0710_mux_usb.h 2007-01-17 00:52:23.000000000 +0100 ++++ linux-2.6.16/drivers/char/ts0710_mux_usb.h 2007-01-17 00:52:26.000000000 +0100 +@@ -27,3 +27,6 @@ + extern struct tty_struct *usb_for_mux_tty; + extern void (*usb_mux_dispatcher)(struct tty_struct *tty); + extern void (*usb_mux_sender)(void); ++ ++extern int get_from_inbuf_list(const unsigned char *buf, int dst_count); ++ diff --git a/packages/linux/linux-ezx-2.6.20.7/mux-remove-get_halted_bit.patch b/packages/linux/linux-ezx-2.6.20.7/mux-remove-get_halted_bit.patch new file mode 100644 index 0000000000..0ebe27d03b --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/mux-remove-get_halted_bit.patch @@ -0,0 +1,22 @@ +Index: linux-2.6.16/drivers/char/ts0710_mux_usb.c +=================================================================== +--- linux-2.6.16.orig/drivers/char/ts0710_mux_usb.c 2007-01-17 01:06:21.000000000 +0100 ++++ linux-2.6.16/drivers/char/ts0710_mux_usb.c 2007-01-17 01:06:31.000000000 +0100 +@@ -461,7 +461,7 @@ + ipcusb_xmit_data(); + } + +-extern void get_halted_bit(void); ++//extern void get_halted_bit(void); + + static void usbipc_bh_bp_func(unsigned long param) + { +@@ -472,7 +472,7 @@ + "UHCRHPS3=0x%x", UHCRHPS3); + } + if (bvd_ipc->ipc_flag == IPC_USB_PROBE_READY) { +- get_halted_bit(); ++ //get_halted_bit(); + + /*send a IN token*/ + bvd_ipc->readurb_mux.dev = bvd_ipc->ipc_dev; diff --git a/packages/linux/linux-ezx-2.6.20.7/mux-remove-usbh_finished_resume.patch b/packages/linux/linux-ezx-2.6.20.7/mux-remove-usbh_finished_resume.patch new file mode 100644 index 0000000000..c415ded428 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/mux-remove-usbh_finished_resume.patch @@ -0,0 +1,22 @@ +Index: linux-2.6.16/drivers/char/ts0710_mux_usb.c +=================================================================== +--- linux-2.6.16.orig/drivers/char/ts0710_mux_usb.c 2007-01-17 01:12:23.000000000 +0100 ++++ linux-2.6.16/drivers/char/ts0710_mux_usb.c 2007-01-17 01:12:37.000000000 +0100 +@@ -97,7 +97,6 @@ + static int sumbit_times = 0; + static int callback_times = 0; + //static unsigned long last_jiff = 0; +-extern int usbh_finished_resume; + /*end global values defined*/ + + MODULE_AUTHOR(DRIVER_AUTHOR); +@@ -546,9 +545,6 @@ + void usb_send_readurb(void) + { + //printk("usb_send_readurb: begining!UHCRHPS3=0x%x, usbh_finished_resume=%d\n", UHCRHPS3, usbh_finished_resume); +- +- if (usbh_finished_resume == 0) +- return; + + tasklet_schedule(&bvd_ipc->bh_bp); + } diff --git a/packages/linux/linux-ezx-2.6.20.7/mux_cli.patch b/packages/linux/linux-ezx-2.6.20.7/mux_cli.patch new file mode 100644 index 0000000000..c86e3b40e4 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/mux_cli.patch @@ -0,0 +1,5395 @@ +Index: linux-2.6.20.7/drivers/char/Kconfig +=================================================================== +--- linux-2.6.20.7.orig/drivers/char/Kconfig 2007-04-13 22:48:14.000000000 +0200 ++++ linux-2.6.20.7/drivers/char/Kconfig 2007-04-21 18:04:56.000000000 +0200 +@@ -1030,5 +1030,17 @@ + sysfs directory, /sys/devices/platform/telco_clock, with a number of + files for controlling the behavior of this hardware. + ++config TS0710_MUX ++ tristate "GSM TS 07.10 Multiplex driver" ++ help ++ This implements the GSM 07.10 multiplex. ++ ++config TS0710_MUX_USB ++ tristate "Motorola USB support for TS 07.10 Multiplex driver" ++ depends on TS0710_MUX ++ help ++ This ads support for TS 07.10 over USB, as found in motorola ++ Smartphones. ++ + endmenu + +Index: linux-2.6.20.7/drivers/char/Makefile +=================================================================== +--- linux-2.6.20.7.orig/drivers/char/Makefile 2007-04-13 22:48:14.000000000 +0200 ++++ linux-2.6.20.7/drivers/char/Makefile 2007-04-21 18:06:42.000000000 +0200 +@@ -101,6 +101,9 @@ + obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o + obj-$(CONFIG_TCG_TPM) += tpm/ + ++obj-$(CONFIG_TS0710_MUX) += ts0710_mux.o ts0710_mux_usb.o ++ ++ + # Files generated that shall be removed upon make clean + clean-files := consolemap_deftbl.c defkeymap.c + +Index: linux-2.6.20.7/drivers/char/ts0710.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/drivers/char/ts0710.h 2007-04-21 18:04:56.000000000 +0200 +@@ -0,0 +1,368 @@ ++/* ++ * File: ts0710.h ++ * ++ * Portions derived from rfcomm.c, original header as follows: ++ * ++ * Copyright (C) 2000, 2001 Axis Communications AB ++ * ++ * Author: Mats Friden <mats.friden@axis.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * 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. ++ * ++ * Exceptionally, Axis Communications AB grants discretionary and ++ * conditional permissions for additional use of the text contained ++ * in the company's release of the AXIS OpenBT Stack under the ++ * provisions set forth hereunder. ++ * ++ * Provided that, if you use the AXIS OpenBT Stack with other files, ++ * that do not implement functionality as specified in the Bluetooth ++ * System specification, to produce an executable, this does not by ++ * itself cause the resulting executable to be covered by the GNU ++ * General Public License. Your use of that executable is in no way ++ * restricted on account of using the AXIS OpenBT Stack code with it. ++ * ++ * This exception does not however invalidate any other reasons why ++ * the executable file might be covered by the provisions of the GNU ++ * General Public License. ++ * ++ */ ++/* ++ * Copyright (C) 2002 Motorola ++ * ++ * 07/28/2002 Initial version based on rfcomm.c ++ * 11/18/2002 Modified ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/fcntl.h> ++#include <linux/string.h> ++#include <linux/major.h> ++#include <linux/mm.h> ++#include <linux/init.h> ++#include <linux/devfs_fs_kernel.h> ++ ++#include <asm/uaccess.h> ++#include <asm/system.h> ++#include <asm/bitops.h> ++ ++#include <asm/byteorder.h> ++#include <asm/types.h> ++ ++#define TS0710_MAX_CHN 14 ++ ++#define SET_PF(ctr) ((ctr) | (1 << 4)) ++#define CLR_PF(ctr) ((ctr) & 0xef) ++#define GET_PF(ctr) (((ctr) >> 4) & 0x1) ++ ++#define GET_PN_MSG_FRAME_SIZE(pn) ( ((pn)->frame_sizeh << 8) | ((pn)->frame_sizel)) ++#define SET_PN_MSG_FRAME_SIZE(pn, size) ({ (pn)->frame_sizel = (size) & 0xff; \ ++ (pn)->frame_sizeh = (size) >> 8; }) ++ ++#define GET_LONG_LENGTH(a) ( ((a).h_len << 7) | ((a).l_len) ) ++#define SET_LONG_LENGTH(a, length) ({ (a).ea = 0; \ ++ (a).l_len = length & 0x7F; \ ++ (a).h_len = (length >> 7) & 0xFF; }) ++ ++#define SHORT_CRC_CHECK 3 ++#define LONG_CRC_CHECK 4 ++ ++/* FIXME: Should thsi one be define here? */ ++#define SHORT_PAYLOAD_SIZE 127 ++ ++#define EA 1 ++#define FCS_SIZE 1 ++#define FLAG_SIZE 2 ++ ++#define TS0710_MAX_HDR_SIZE 5 ++#define DEF_TS0710_MTU 256 ++ ++#define TS0710_BASIC_FLAG 0xF9 ++/* the control field */ ++#define SABM 0x2f ++#define SABM_SIZE 4 ++#define UA 0x63 ++#define UA_SIZE 4 ++#define DM 0x0f ++#define DISC 0x43 ++#define UIH 0xef ++ ++/* the type field in a multiplexer command packet */ ++#define TEST 0x8 ++#define FCON 0x28 ++#define FCOFF 0x18 ++#define MSC 0x38 ++#define RPN 0x24 ++#define RLS 0x14 ++#define PN 0x20 ++#define NSC 0x4 ++ ++/* V.24 modem control signals */ ++#define FC 0x2 ++#define RTC 0x4 ++#define RTR 0x8 ++#define IC 0x40 ++#define DV 0x80 ++ ++#define CTRL_CHAN 0 /* The control channel is defined as DLCI 0 */ ++#define MCC_CMD 1 /* Multiplexer command cr */ ++#define MCC_RSP 0 /* Multiplexer response cr */ ++ ++#ifdef __LITTLE_ENDIAN_BITFIELD ++ ++typedef struct { ++ __u8 ea:1; ++ __u8 cr:1; ++ __u8 d:1; ++ __u8 server_chn:5; ++} __attribute__ ((packed)) address_field; ++ ++typedef struct { ++ __u8 ea:1; ++ __u8 len:7; ++} __attribute__ ((packed)) short_length; ++ ++typedef struct { ++ __u8 ea:1; ++ __u8 l_len:7; ++ __u8 h_len; ++} __attribute__ ((packed)) long_length; ++ ++typedef struct { ++ address_field addr; ++ __u8 control; ++ short_length length; ++} __attribute__ ((packed)) short_frame_head; ++ ++typedef struct { ++ short_frame_head h; ++ __u8 data[0]; ++} __attribute__ ((packed)) short_frame; ++ ++typedef struct { ++ address_field addr; ++ __u8 control; ++ long_length length; ++ __u8 data[0]; ++} __attribute__ ((packed)) long_frame_head; ++ ++typedef struct { ++ long_frame_head h; ++ __u8 data[0]; ++} __attribute__ ((packed)) long_frame; ++ ++/* Typedefinitions for structures used for the multiplexer commands */ ++typedef struct { ++ __u8 ea:1; ++ __u8 cr:1; ++ __u8 type:6; ++} __attribute__ ((packed)) mcc_type; ++ ++typedef struct { ++ mcc_type type; ++ short_length length; ++ __u8 value[0]; ++} __attribute__ ((packed)) mcc_short_frame_head; ++ ++typedef struct { ++ mcc_short_frame_head h; ++ __u8 value[0]; ++} __attribute__ ((packed)) mcc_short_frame; ++ ++typedef struct { ++ mcc_type type; ++ long_length length; ++ __u8 value[0]; ++} __attribute__ ((packed)) mcc_long_frame_head; ++ ++typedef struct { ++ mcc_long_frame_head h; ++ __u8 value[0]; ++} __attribute__ ((packed)) mcc_long_frame; ++ ++/* MSC-command */ ++typedef struct { ++ __u8 ea:1; ++ __u8 fc:1; ++ __u8 rtc:1; ++ __u8 rtr:1; ++ __u8 reserved:2; ++ __u8 ic:1; ++ __u8 dv:1; ++} __attribute__ ((packed)) v24_sigs; ++ ++typedef struct { ++ __u8 ea:1; ++ __u8 b1:1; ++ __u8 b2:1; ++ __u8 b3:1; ++ __u8 len:4; ++} __attribute__ ((packed)) brk_sigs; ++ ++typedef struct { ++ short_frame_head s_head; ++ mcc_short_frame_head mcc_s_head; ++ address_field dlci; ++ __u8 v24_sigs; ++ //brk_sigs break_signals; ++ __u8 fcs; ++} __attribute__ ((packed)) msc_msg; ++ ++#if 0 ++/* conflict with termios.h */ ++/* RPN command */ ++#define B2400 0 ++#define B4800 1 ++#define B7200 2 ++#define B9600 3 ++#define B19200 4 ++#define B38400 5 ++#define B57600 6 ++#define B115200 7 ++#define D230400 8 ++#endif ++ ++/* ++typedef struct{ ++ __u8 bit_rate:1; ++ __u8 data_bits:1; ++ __u8 stop_bit:1; ++ __u8 parity:1; ++ __u8 parity_type:1; ++ __u8 xon_u8:1; ++ __u8 xoff_u8:1; ++ __u8 res1:1; ++ __u8 xon_input:1; ++ __u8 xon_output:1; ++ __u8 rtr_input:1; ++ __u8 rtr_output:1; ++ __u8 rtc_input:1; ++ __u8 rtc_output:1; ++ __u8 res2:2; ++} __attribute__((packed)) parameter_mask; ++ ++typedef struct{ ++ __u8 bit_rate; ++ __u8 data_bits:2; ++ __u8 stop_bit:1; ++ __u8 parity:1; ++ __u8 parity_type:2; ++ __u8 res1:2; ++ __u8 xon_input:1; ++ __u8 xon_output:1; ++ __u8 rtr_input:1; ++ __u8 rtr_output:1; ++ __u8 rtc_input:1; ++ __u8 rtc_output:1; ++ __u8 res2:2; ++ __u8 xon_u8; ++ __u8 xoff_u8; ++ parameter_mask pm; ++} __attribute__((packed)) rpn_values; ++ ++typedef struct{ ++ short_frame_head s_head; ++ mcc_short_frame_head mcc_s_head; ++ address_field dlci; ++ rpn_values rpn_val; ++ __u8 fcs; ++} __attribute__((packed)) rpn_msg; ++*/ ++ ++/* RLS-command */ ++/* ++typedef struct{ ++ short_frame_head s_head; ++ mcc_short_frame_head mcc_s_head; ++ address_field dlci; ++ __u8 error:4; ++ __u8 res:4; ++ __u8 fcs; ++} __attribute__((packed)) rls_msg; ++*/ ++ ++/* PN-command */ ++typedef struct { ++ short_frame_head s_head; ++ mcc_short_frame_head mcc_s_head; ++ __u8 dlci:6; ++ __u8 res1:2; ++ __u8 frame_type:4; ++ __u8 credit_flow:4; ++ __u8 prior:6; ++ __u8 res2:2; ++ __u8 ack_timer; ++ __u8 frame_sizel; ++ __u8 frame_sizeh; ++ __u8 max_nbrof_retrans; ++ __u8 credits; ++ __u8 fcs; ++} __attribute__ ((packed)) pn_msg; ++ ++/* NSC-command */ ++typedef struct { ++ short_frame_head s_head; ++ mcc_short_frame_head mcc_s_head; ++ mcc_type command_type; ++ __u8 fcs; ++} __attribute__ ((packed)) nsc_msg; ++ ++#else ++#error Only littel-endianess supported now! ++#endif ++ ++enum { ++ REJECTED = 0, ++ DISCONNECTED, ++ CONNECTING, ++ NEGOTIATING, ++ CONNECTED, ++ DISCONNECTING, ++ FLOW_STOPPED ++}; ++ ++enum ts0710_events { ++ CONNECT_IND, ++ CONNECT_CFM, ++ DISCONN_CFM ++}; ++ ++typedef struct { ++ volatile __u8 state; ++ volatile __u8 flow_control; ++ volatile __u8 initiated; ++ volatile __u8 initiator; ++ volatile __u16 mtu; ++ wait_queue_head_t open_wait; ++ wait_queue_head_t close_wait; ++} dlci_struct; ++ ++/* user space interfaces */ ++typedef struct { ++ volatile __u8 initiator; ++ volatile __u8 c_dlci; ++ volatile __u16 mtu; ++ volatile __u8 be_testing; ++ volatile __u32 test_errs; ++ wait_queue_head_t test_wait; ++ ++ dlci_struct dlci[TS0710_MAX_CHN]; ++} ts0710_con; +Index: linux-2.6.20.7/drivers/char/ts0710_mux.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/drivers/char/ts0710_mux.c 2007-04-21 18:08:02.000000000 +0200 +@@ -0,0 +1,3966 @@ ++/* ++ * File: mux_driver.c ++ * ++ * Portions derived from rfcomm.c, original header as follows: ++ * ++ * Copyright (C) 2000, 2001 Axis Communications AB ++ * ++ * Author: Mats Friden <mats.friden@axis.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * 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. ++ * ++ * Exceptionally, Axis Communications AB grants discretionary and ++ * conditional permissions for additional use of the text contained ++ * in the company's release of the AXIS OpenBT Stack under the ++ * provisions set forth hereunder. ++ * ++ * Provided that, if you use the AXIS OpenBT Stack with other files, ++ * that do not implement functionality as specified in the Bluetooth ++ * System specification, to produce an executable, this does not by ++ * itself cause the resulting executable to be covered by the GNU ++ * General Public License. Your use of that executable is in no way ++ * restricted on account of using the AXIS OpenBT Stack code with it. ++ * ++ * This exception does not however invalidate any other reasons why ++ * the executable file might be covered by the provisions of the GNU ++ * General Public License. ++ * ++ */ ++/* ++ * Copyright (C) 2002-2004 Motorola ++ * Copyright (C) 2006 Harald Welte <laforge@openezx.org> ++ * ++ * 07/28/2002 Initial version ++ * 11/18/2002 Second version ++ * 04/21/2004 Add GPRS PROC ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/types.h> ++ ++#include <linux/kernel.h> ++#include <linux/proc_fs.h> ++ ++#define USB_FOR_MUX ++ ++#ifndef USB_FOR_MUX ++#include <linux/serial.h> ++#endif ++ ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/fcntl.h> ++#include <linux/string.h> ++#include <linux/major.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/devfs_fs_kernel.h> ++//#include <syslog.h> ++ ++#include <asm/uaccess.h> ++#include <asm/system.h> ++#include <asm/bitops.h> ++ ++#ifdef USB_FOR_MUX ++//#include <linux/usb.h> ++#include "ts0710_mux_usb.h" ++#endif ++ ++#include "ts0710.h" ++#include "ts0710_mux.h" ++ ++#define TS0710MUX_GPRS_SESSION_MAX 2 ++#define TS0710MUX_MAJOR 250 ++#define TS0710MUX_MINOR_START 0 ++#define NR_MUXS 16 ++ ++ /*#define TS0710MUX_TIME_OUT 30 *//* 300ms */ ++#define TS0710MUX_TIME_OUT 250 /* 2500ms, for BP UART hardware flow control AP UART */ ++ ++#define TS0710MUX_IO_DLCI_FC_ON 0x54F2 ++#define TS0710MUX_IO_DLCI_FC_OFF 0x54F3 ++#define TS0710MUX_IO_FC_ON 0x54F4 ++#define TS0710MUX_IO_FC_OFF 0x54F5 ++ ++#define TS0710MUX_MAX_BUF_SIZE 2048 ++ ++#define TS0710MUX_SEND_BUF_OFFSET 10 ++#define TS0710MUX_SEND_BUF_SIZE (DEF_TS0710_MTU + TS0710MUX_SEND_BUF_OFFSET + 34) ++#define TS0710MUX_RECV_BUF_SIZE TS0710MUX_SEND_BUF_SIZE ++ ++/*For BP UART problem Begin*/ ++#ifdef TS0710SEQ2 ++#define ACK_SPACE 66 /* 6 * 11(ACK frame size) */ ++#else ++#define ACK_SPACE 42 /* 6 * 7(ACK frame size) */ ++#endif ++/*For BP UART problem End*/ ++ ++ /*#define TS0710MUX_SERIAL_BUF_SIZE (DEF_TS0710_MTU + TS0710_MAX_HDR_SIZE)*//* For BP UART problem */ ++#define TS0710MUX_SERIAL_BUF_SIZE (DEF_TS0710_MTU + TS0710_MAX_HDR_SIZE + ACK_SPACE) /* For BP UART problem: ACK_SPACE */ ++ ++#define TS0710MUX_MAX_TOTAL_FRAME_SIZE (DEF_TS0710_MTU + TS0710_MAX_HDR_SIZE + FLAG_SIZE) ++#define TS0710MUX_MAX_CHARS_IN_BUF 65535 ++#define TS0710MUX_THROTTLE_THRESHOLD DEF_TS0710_MTU ++ ++#define TEST_PATTERN_SIZE 250 ++ ++#define CMDTAG 0x55 ++#define DATATAG 0xAA ++ ++#define ACK 0x4F /*For BP UART problem */ ++ ++/*For BP UART problem Begin*/ ++#ifdef TS0710SEQ2 ++#define FIRST_BP_SEQ_OFFSET 1 /*offset from start flag */ ++#define SECOND_BP_SEQ_OFFSET 2 /*offset from start flag */ ++#define FIRST_AP_SEQ_OFFSET 3 /*offset from start flag */ ++#define SECOND_AP_SEQ_OFFSET 4 /*offset from start flag */ ++#define SLIDE_BP_SEQ_OFFSET 5 /*offset from start flag */ ++#define SEQ_FIELD_SIZE 5 ++#else ++#define SLIDE_BP_SEQ_OFFSET 1 /*offset from start flag */ ++#define SEQ_FIELD_SIZE 1 ++#endif ++ ++#define ADDRESS_FIELD_OFFSET (1 + SEQ_FIELD_SIZE) /*offset from start flag */ ++/*For BP UART problem End*/ ++ ++#ifndef UNUSED_PARAM ++#define UNUSED_PARAM(v) (void)(v) ++#endif ++ ++#define TS0710MUX_GPRS1_DLCI 7 ++#define TS0710MUX_GPRS2_DLCI 8 ++ ++#define TS0710MUX_GPRS1_RECV_COUNT_IDX 0 ++#define TS0710MUX_GPRS1_SEND_COUNT_IDX 1 ++#define TS0710MUX_GPRS2_RECV_COUNT_IDX 2 ++#define TS0710MUX_GPRS2_SEND_COUNT_IDX 3 ++#define TS0710MUX_COUNT_MAX_IDX 3 ++#define TS0710MUX_COUNT_IDX_NUM (TS0710MUX_COUNT_MAX_IDX + 1) ++ ++static volatile int mux_data_count[TS0710MUX_COUNT_IDX_NUM] = { 0, 0, 0, 0 }; ++static volatile int mux_data_count2[TS0710MUX_COUNT_IDX_NUM] = { 0, 0, 0, 0 }; ++static struct semaphore mux_data_count_mutex[TS0710MUX_COUNT_IDX_NUM]; ++static volatile __u8 post_recv_count_flag = 0; ++ ++/*PROC file*/ ++struct proc_dir_entry *gprs_proc_file = NULL; ++ssize_t file_proc_read(struct file *file, char *buf, size_t size, ++ loff_t * ppos); ++ssize_t file_proc_write(struct file *file, const char *buf, size_t count, ++ loff_t * ppos); ++struct file_operations file_proc_operations = { ++ read:file_proc_read, ++ write:file_proc_write, ++}; ++typedef struct { ++ int recvBytes; ++ int sentBytes; ++} gprs_bytes; ++ ++static __u8 tty2dlci[NR_MUXS] = ++ { 1, 2, 3, 4, 5, 6, 7, 8, 6, 7, 8, 9, 10, 11, 12, 13 }; ++static __u8 iscmdtty[NR_MUXS] = ++ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; ++typedef struct { ++ __u8 cmdtty; ++ __u8 datatty; ++} dlci_tty; ++static dlci_tty dlci2tty[] = { {0, 0}, /* DLCI 0 */ ++{0, 0}, /* DLCI 1 */ ++{1, 1}, /* DLCI 2 */ ++{2, 2}, /* DLCI 3 */ ++{3, 3}, /* DLCI 4 */ ++{4, 4}, /* DLCI 5 */ ++{5, 8}, /* DLCI 6 */ ++{6, 9}, /* DLCI 7 */ ++{7, 10}, /* DLCI 8 */ ++{11, 11}, /* DLCI 9 */ ++{12, 12}, /* DLCI 10 */ ++{13, 13}, /* DLCI 11 */ ++{14, 14}, /* DLCI 12 */ ++{15, 15} ++}; /* DLCI 13 */ ++ ++typedef struct { ++ volatile __u8 buf[TS0710MUX_SEND_BUF_SIZE]; ++ volatile __u8 *frame; ++ unsigned long flags; ++ volatile __u16 length; ++ volatile __u8 filled; ++ volatile __u8 dummy; /* Allignment to 4*n bytes */ ++} mux_send_struct; ++ ++/* Bit number in flags of mux_send_struct */ ++#define BUF_BUSY 0 ++ ++struct mux_recv_packet_tag { ++ __u8 *data; ++ __u32 length; ++ struct mux_recv_packet_tag *next; ++}; ++typedef struct mux_recv_packet_tag mux_recv_packet; ++ ++struct mux_recv_struct_tag { ++ __u8 data[TS0710MUX_RECV_BUF_SIZE]; ++ __u32 length; ++ __u32 total; ++ mux_recv_packet *mux_packet; ++ struct mux_recv_struct_tag *next; ++ int no_tty; ++ volatile __u8 post_unthrottle; ++}; ++typedef struct mux_recv_struct_tag mux_recv_struct; ++ ++#define RECV_RUNNING 0 ++static unsigned long mux_recv_flags = 0; ++ ++static mux_send_struct *mux_send_info[NR_MUXS]; ++static volatile __u8 mux_send_info_flags[NR_MUXS]; ++static volatile __u8 mux_send_info_idx = NR_MUXS; ++ ++static mux_recv_struct *mux_recv_info[NR_MUXS]; ++static volatile __u8 mux_recv_info_flags[NR_MUXS]; ++static mux_recv_struct *mux_recv_queue = NULL; ++ ++static struct tty_driver mux_driver; ++ ++#ifdef USB_FOR_MUX ++#define COMM_FOR_MUX_DRIVER usb_for_mux_driver ++#define COMM_FOR_MUX_TTY usb_for_mux_tty ++#define COMM_MUX_DISPATCHER usb_mux_dispatcher ++#define COMM_MUX_SENDER usb_mux_sender ++#else ++#define COMM_FOR_MUX_DRIVER serial_for_mux_driver ++#define COMM_FOR_MUX_TTY serial_for_mux_tty ++#define COMM_MUX_DISPATCHER serial_mux_dispatcher ++#define COMM_MUX_SENDER serial_mux_sender ++ ++extern struct list_head *tq_serial_for_mux; ++#endif ++ ++extern struct tty_driver *COMM_FOR_MUX_DRIVER; ++extern struct tty_struct *COMM_FOR_MUX_TTY; ++extern void (*COMM_MUX_DISPATCHER) (struct tty_struct * tty); ++extern void (*COMM_MUX_SENDER) (void); ++ ++static struct work_struct send_tqueue; ++static struct work_struct receive_tqueue; ++static struct work_struct post_recv_tqueue; ++ ++static struct tty_struct *mux_table[NR_MUXS]; ++static struct termios *mux_termios[NR_MUXS]; ++static struct termios *mux_termios_locked[NR_MUXS]; ++static volatile short int mux_tty[NR_MUXS]; ++ ++#ifdef min ++#undef min ++#define min(a,b) ( (a)<(b) ? (a):(b) ) ++#endif ++ ++static int get_count(__u8 idx); ++static int set_count(__u8 idx, int count); ++static int add_count(__u8 idx, int count); ++ ++static int send_ua(ts0710_con * ts0710, __u8 dlci); ++static int send_dm(ts0710_con * ts0710, __u8 dlci); ++static int send_sabm(ts0710_con * ts0710, __u8 dlci); ++static int send_disc(ts0710_con * ts0710, __u8 dlci); ++static void queue_uih(mux_send_struct * send_info, __u16 len, ++ ts0710_con * ts0710, __u8 dlci); ++static int send_pn_msg(ts0710_con * ts0710, __u8 prior, __u32 frame_size, ++ __u8 credit_flow, __u8 credits, __u8 dlci, __u8 cr); ++static int send_nsc_msg(ts0710_con * ts0710, mcc_type cmd, __u8 cr); ++static void set_uih_hdr(short_frame * uih_pkt, __u8 dlci, __u32 len, __u8 cr); ++ ++static __u32 crc_check(__u8 * data, __u32 length, __u8 check_sum); ++static __u8 crc_calc(__u8 * data, __u32 length); ++static void create_crctable(__u8 table[]); ++ ++static void mux_sched_send(void); ++ ++static __u8 crctable[256]; ++ ++static ts0710_con ts0710_connection; ++/* ++static rpn_values rpn_val; ++*/ ++ ++static int valid_dlci(__u8 dlci) ++{ ++ if ((dlci < TS0710_MAX_CHN) && (dlci > 0)) ++ return 1; ++ else ++ return 0; ++} ++ ++#ifdef TS0710DEBUG ++ ++#ifdef PRINT_OUTPUT_PRINTK ++#define TS0710_DEBUG(fmt, arg...) printk(KERN_INFO "MUX " __FUNCTION__ ": " fmt "\n" , ## arg) ++#else ++#include "ezxlog.h" ++static __u8 strDebug[256]; ++#define TS0710_DEBUG(fmt, arg...) ({ snprintf(strDebug, sizeof(strDebug), "MUX " __FUNCTION__ ": " fmt "\n" , ## arg); \ ++ /*printk("%s", strDebug)*/ezxlogk("MX", strDebug, strlen(strDebug)); }) ++#endif /* End #ifdef PRINT_OUTPUT_PRINTK */ ++ ++#else ++#define TS0710_DEBUG(fmt...) ++#endif /* End #ifdef TS0710DEBUG */ ++ ++#ifdef TS0710LOG ++static unsigned char g_tbuf[TS0710MUX_MAX_BUF_SIZE]; ++#ifdef PRINT_OUTPUT_PRINTK ++#define TS0710_LOG(fmt, arg...) printk(fmt, ## arg) ++#define TS0710_PRINTK(fmt, arg...) printk(fmt, ## arg) ++#else ++#include "ezxlog.h" ++static __u8 strLog[256]; ++#define TS0710_LOG(fmt, arg...) ({ snprintf(strLog, sizeof(strLog), fmt, ## arg); \ ++ /*printk("%s", strLog)*/ezxlogk("MX", strLog, strlen(strLog)); }) ++#define TS0710_PRINTK(fmt, arg...) ({ printk(fmt, ## arg); \ ++ TS0710_LOG(fmt, ## arg); }) ++#endif /* End #ifdef PRINT_OUTPUT_PRINTK */ ++ ++#else ++#define TS0710_LOG(fmt...) ++#define TS0710_PRINTK(fmt, arg...) printk(fmt, ## arg) ++#endif /* End #ifdef TS0710LOG */ ++ ++#ifdef TS0710DEBUG ++static void TS0710_DEBUGHEX(__u8 * buf, int len) ++{ ++ static unsigned char tbuf[TS0710MUX_MAX_BUF_SIZE]; ++ ++ int i; ++ int c; ++ ++ if (len <= 0) { ++ return; ++ } ++ ++ c = 0; ++ for (i = 0; (i < len) && (c < (TS0710MUX_MAX_BUF_SIZE - 3)); i++) { ++ sprintf(&tbuf[c], "%02x ", buf[i]); ++ c += 3; ++ } ++ tbuf[c] = 0; ++ ++#ifdef PRINT_OUTPUT_PRINTK ++ TS0710_DEBUG("%s", tbuf); ++#else ++ /*printk("%s\n", tbuf) */ ezxlogk("MX", tbuf, c); ++#endif ++} ++static void TS0710_DEBUGSTR(__u8 * buf, int len) ++{ ++ static unsigned char tbuf[TS0710MUX_MAX_BUF_SIZE]; ++ ++ if (len <= 0) { ++ return; ++ } ++ ++ if (len > (TS0710MUX_MAX_BUF_SIZE - 1)) { ++ len = (TS0710MUX_MAX_BUF_SIZE - 1); ++ } ++ ++ memcpy(tbuf, buf, len); ++ tbuf[len] = 0; ++ ++#ifdef PRINT_OUTPUT_PRINTK ++ /* 0x00 byte in the string pointed by tbuf may truncate the print result */ ++ TS0710_DEBUG("%s", tbuf); ++#else ++ /*printk("%s\n", tbuf) */ ezxlogk("MX", tbuf, len); ++#endif ++} ++#else ++#define TS0710_DEBUGHEX(buf, len) ++#define TS0710_DEBUGSTR(buf, len) ++#endif /* End #ifdef TS0710DEBUG */ ++ ++#ifdef TS0710LOG ++static void TS0710_LOGSTR_FRAME(__u8 send, __u8 * data, int len) ++{ ++ short_frame *short_pkt; ++ long_frame *long_pkt; ++ __u8 *uih_data_start; ++ __u32 uih_len; ++ __u8 dlci; ++ int pos; ++ ++ if (len <= 0) { ++ return; ++ } ++ ++ pos = 0; ++ if (send) { ++ pos += sprintf(&g_tbuf[pos], "<"); ++ short_pkt = (short_frame *) (data + 1); /*For BP UART problem */ ++ } else { ++ /*For BP UART problem */ ++ /*pos += sprintf(&g_tbuf[pos], ">"); */ ++ pos += sprintf(&g_tbuf[pos], ">%d ", *(data + SLIDE_BP_SEQ_OFFSET)); /*For BP UART problem */ ++ ++#ifdef TS0710SEQ2 ++ pos += sprintf(&g_tbuf[pos], "%02x %02x %02x %02x ", *(data + FIRST_BP_SEQ_OFFSET), *(data + SECOND_BP_SEQ_OFFSET), *(data + FIRST_AP_SEQ_OFFSET), *(data + SECOND_AP_SEQ_OFFSET)); /*For BP UART problem */ ++#endif ++ ++ short_pkt = (short_frame *) (data + ADDRESS_FIELD_OFFSET); /*For BP UART problem */ ++ } ++ ++ /*For BP UART problem */ ++ /*short_pkt = (short_frame *)(data + 1); */ ++ ++ dlci = short_pkt->h.addr.server_chn << 1 | short_pkt->h.addr.d; ++ switch (CLR_PF(short_pkt->h.control)) { ++ case SABM: ++ pos += sprintf(&g_tbuf[pos], "C SABM %d ::", dlci); ++ break; ++ case UA: ++ pos += sprintf(&g_tbuf[pos], "C UA %d ::", dlci); ++ break; ++ case DM: ++ pos += sprintf(&g_tbuf[pos], "C DM %d ::", dlci); ++ break; ++ case DISC: ++ pos += sprintf(&g_tbuf[pos], "C DISC %d ::", dlci); ++ break; ++ ++ /*For BP UART problem Begin */ ++ case ACK: ++ pos += sprintf(&g_tbuf[pos], "C ACK %d ", short_pkt->data[0]); ++ ++#ifdef TS0710SEQ2 ++ pos += sprintf(&g_tbuf[pos], "%02x %02x %02x %02x ", short_pkt->data[1], short_pkt->data[2], short_pkt->data[3], short_pkt->data[4]); /*For BP UART problem */ ++#endif ++ ++ pos += sprintf(&g_tbuf[pos], "::"); ++ break; ++ /*For BP UART problem End */ ++ ++ case UIH: ++ if (!dlci) { ++ pos += sprintf(&g_tbuf[pos], "C MCC %d ::", dlci); ++ } else { ++ ++ if ((short_pkt->h.length.ea) == 0) { ++ long_pkt = (long_frame *) short_pkt; ++ uih_len = GET_LONG_LENGTH(long_pkt->h.length); ++ uih_data_start = long_pkt->h.data; ++ } else { ++ uih_len = short_pkt->h.length.len; ++ uih_data_start = short_pkt->data; ++ } ++ switch (*uih_data_start) { ++ case CMDTAG: ++ pos += ++ sprintf(&g_tbuf[pos], "I %d A %d ::", dlci, ++ uih_len); ++ break; ++ case DATATAG: ++ default: ++ pos += ++ sprintf(&g_tbuf[pos], "I %d D %d ::", dlci, ++ uih_len); ++ break; ++ } ++ ++ } ++ break; ++ default: ++ pos += sprintf(&g_tbuf[pos], "N!!! %d ::", dlci); ++ break; ++ } ++ ++ if (len > (sizeof(g_tbuf) - pos - 1)) { ++ len = (sizeof(g_tbuf) - pos - 1); ++ } ++ ++ memcpy(&g_tbuf[pos], data, len); ++ pos += len; ++ g_tbuf[pos] = 0; ++ ++#ifdef PRINT_OUTPUT_PRINTK ++ /* 0x00 byte in the string pointed by g_tbuf may truncate the print result */ ++ TS0710_LOG("%s\n", g_tbuf); ++#else ++ /*printk("%s\n", g_tbuf) */ ezxlogk("MX", g_tbuf, pos); ++#endif ++} ++#else ++#define TS0710_LOGSTR_FRAME(send, data, len) ++#endif ++ ++#ifdef TS0710SIG ++#define my_for_each_task(p) \ ++ for ((p) = current; ((p) = (p)->next_task) != current; ) ++ ++static void TS0710_SIG2APLOGD(void) ++{ ++ struct task_struct *p; ++ static __u8 sig = 0; ++ ++ if (sig) { ++ return; ++ } ++ ++ read_lock(&tasklist_lock); ++ my_for_each_task(p) { ++ if (strncmp(p->comm, "aplogd", 6) == 0) { ++ sig = 1; ++ if (send_sig(SIGUSR2, p, 1) == 0) { ++ TS0710_PRINTK ++ ("MUX: success to send SIGUSR2 to aplogd!\n"); ++ } else { ++ TS0710_PRINTK ++ ("MUX: failure to send SIGUSR2 to aplogd!\n"); ++ } ++ break; ++ } ++ } ++ read_unlock(&tasklist_lock); ++ ++ if (!sig) { ++ TS0710_PRINTK("MUX: not found aplogd!\n"); ++ } ++} ++#else ++#define TS0710_SIG2APLOGD() ++#endif ++ ++static int basic_write(ts0710_con * ts0710, __u8 * buf, int len) ++{ ++ int res; ++ ++ UNUSED_PARAM(ts0710); ++ ++ buf[0] = TS0710_BASIC_FLAG; ++ buf[len + 1] = TS0710_BASIC_FLAG; ++ ++ if ((COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)) { ++ TS0710_PRINTK ++ ("MUX basic_write: (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)\n"); ++ ++#ifndef USB_FOR_MUX ++ TS0710_PRINTK ++ ("MUX basic_write: tapisrv might be down!!! (serial_for_mux_driver == 0) || (serial_for_mux_tty == 0)\n"); ++ TS0710_SIG2APLOGD(); ++#endif ++ ++ return -1; ++ } ++ ++ TS0710_LOGSTR_FRAME(1, buf, len + 2); ++ TS0710_DEBUGHEX(buf, len + 2); ++ ++ res = COMM_FOR_MUX_DRIVER->write(COMM_FOR_MUX_TTY, buf, len + 2); ++ ++ if (res != len + 2) { ++ TS0710_PRINTK("MUX basic_write: Write Error!\n"); ++ return -1; ++ } ++ ++ return len + 2; ++} ++ ++/* Functions for the crc-check and calculation */ ++ ++#define CRC_VALID 0xcf ++ ++static __u32 crc_check(__u8 * data, __u32 length, __u8 check_sum) ++{ ++ __u8 fcs = 0xff; ++ ++ while (length--) { ++ fcs = crctable[fcs ^ *data++]; ++ } ++ fcs = crctable[fcs ^ check_sum]; ++ TS0710_DEBUG("fcs : %d\n", fcs); ++ if (fcs == (uint) 0xcf) { /*CRC_VALID) */ ++ TS0710_DEBUG("crc_check: CRC check OK\n"); ++ return 0; ++ } else { ++ TS0710_PRINTK("MUX crc_check: CRC check failed\n"); ++ return 1; ++ } ++} ++ ++/* Calculates the checksum according to the ts0710 specification */ ++ ++static __u8 crc_calc(__u8 * data, __u32 length) ++{ ++ __u8 fcs = 0xff; ++ ++ while (length--) { ++ fcs = crctable[fcs ^ *data++]; ++ } ++ ++ return 0xff - fcs; ++} ++ ++/* Calulates a reversed CRC table for the FCS check */ ++ ++static void create_crctable(__u8 table[]) ++{ ++ int i, j; ++ ++ __u8 data; ++ __u8 code_word = (__u8) 0xe0; ++ __u8 sr = (__u8) 0; ++ ++ for (j = 0; j < 256; j++) { ++ data = (__u8) j; ++ ++ for (i = 0; i < 8; i++) { ++ if ((data & 0x1) ^ (sr & 0x1)) { ++ sr >>= 1; ++ sr ^= code_word; ++ } else { ++ sr >>= 1; ++ } ++ ++ data >>= 1; ++ sr &= 0xff; ++ } ++ ++ table[j] = sr; ++ sr = 0; ++ } ++} ++ ++static void ts0710_reset_dlci(__u8 j) ++{ ++ if (j >= TS0710_MAX_CHN) ++ return; ++ ++ ts0710_connection.dlci[j].state = DISCONNECTED; ++ ts0710_connection.dlci[j].flow_control = 0; ++ ts0710_connection.dlci[j].mtu = DEF_TS0710_MTU; ++ ts0710_connection.dlci[j].initiated = 0; ++ ts0710_connection.dlci[j].initiator = 0; ++ init_waitqueue_head(&ts0710_connection.dlci[j].open_wait); ++ init_waitqueue_head(&ts0710_connection.dlci[j].close_wait); ++} ++ ++static void ts0710_reset_con(void) ++{ ++ __u8 j; ++ ++ ts0710_connection.initiator = 0; ++ ts0710_connection.mtu = DEF_TS0710_MTU + TS0710_MAX_HDR_SIZE; ++ ts0710_connection.be_testing = 0; ++ ts0710_connection.test_errs = 0; ++ init_waitqueue_head(&ts0710_connection.test_wait); ++ ++ for (j = 0; j < TS0710_MAX_CHN; j++) { ++ ts0710_reset_dlci(j); ++ } ++} ++ ++static void ts0710_init(void) ++{ ++ create_crctable(crctable); ++ ++ ts0710_reset_con(); ++ ++ /* Set the values in the rpn octets */ ++/* ++ rpn_val.bit_rate = 7; ++ rpn_val.data_bits = 3; ++ rpn_val.stop_bit = 0; ++ rpn_val.parity = 0; ++ rpn_val.parity_type = 0; ++ rpn_val.res1 = 0; ++ rpn_val.xon_input = 0; ++ rpn_val.xon_output = 0; ++ rpn_val.rtr_input = 0; ++ rpn_val.rtr_output = 0; ++ rpn_val.rtc_input = 0; ++ rpn_val.rtc_output = 0; ++ rpn_val.res2 = 0; ++ rpn_val.xon_u8 = 0x11; ++ rpn_val.xoff_u8 = 0x13; ++ memset(&rpn_val.pm, 0 , 2); *//* Set the mask to zero */ ++} ++ ++static void ts0710_upon_disconnect(void) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ __u8 j; ++ ++ for (j = 0; j < TS0710_MAX_CHN; j++) { ++ ts0710->dlci[j].state = DISCONNECTED; ++ wake_up_interruptible(&ts0710->dlci[j].open_wait); ++ wake_up_interruptible(&ts0710->dlci[j].close_wait); ++ } ++ ts0710->be_testing = 0; ++ wake_up_interruptible(&ts0710->test_wait); ++ ts0710_reset_con(); ++} ++ ++/* Sending packet functions */ ++ ++/* Creates a UA packet and puts it at the beginning of the pkt pointer */ ++ ++static int send_ua(ts0710_con * ts0710, __u8 dlci) ++{ ++ __u8 buf[sizeof(short_frame) + FCS_SIZE + FLAG_SIZE]; ++ short_frame *ua; ++ ++ TS0710_DEBUG("send_ua: Creating UA packet to DLCI %d\n", dlci); ++ ++ ua = (short_frame *) (buf + 1); ++ ua->h.addr.ea = 1; ++ ua->h.addr.cr = ((~(ts0710->initiator)) & 0x1); ++ ua->h.addr.d = (dlci) & 0x1; ++ ua->h.addr.server_chn = (dlci) >> 0x1; ++ ua->h.control = SET_PF(UA); ++ ua->h.length.ea = 1; ++ ua->h.length.len = 0; ++ ua->data[0] = crc_calc((__u8 *) ua, SHORT_CRC_CHECK); ++ ++ return basic_write(ts0710, buf, sizeof(short_frame) + FCS_SIZE); ++} ++ ++/* Creates a DM packet and puts it at the beginning of the pkt pointer */ ++ ++static int send_dm(ts0710_con * ts0710, __u8 dlci) ++{ ++ __u8 buf[sizeof(short_frame) + FCS_SIZE + FLAG_SIZE]; ++ short_frame *dm; ++ ++ TS0710_DEBUG("send_dm: Creating DM packet to DLCI %d\n", dlci); ++ ++ dm = (short_frame *) (buf + 1); ++ dm->h.addr.ea = 1; ++ dm->h.addr.cr = ((~(ts0710->initiator)) & 0x1); ++ dm->h.addr.d = dlci & 0x1; ++ dm->h.addr.server_chn = dlci >> 0x1; ++ dm->h.control = SET_PF(DM); ++ dm->h.length.ea = 1; ++ dm->h.length.len = 0; ++ dm->data[0] = crc_calc((__u8 *) dm, SHORT_CRC_CHECK); ++ ++ return basic_write(ts0710, buf, sizeof(short_frame) + FCS_SIZE); ++} ++ ++static int send_sabm(ts0710_con * ts0710, __u8 dlci) ++{ ++ __u8 buf[sizeof(short_frame) + FCS_SIZE + FLAG_SIZE]; ++ short_frame *sabm; ++ ++ TS0710_DEBUG("send_sabm: Creating SABM packet to DLCI %d\n", dlci); ++ ++ sabm = (short_frame *) (buf + 1); ++ sabm->h.addr.ea = 1; ++ sabm->h.addr.cr = ((ts0710->initiator) & 0x1); ++ sabm->h.addr.d = dlci & 0x1; ++ sabm->h.addr.server_chn = dlci >> 0x1; ++ sabm->h.control = SET_PF(SABM); ++ sabm->h.length.ea = 1; ++ sabm->h.length.len = 0; ++ sabm->data[0] = crc_calc((__u8 *) sabm, SHORT_CRC_CHECK); ++ ++ return basic_write(ts0710, buf, sizeof(short_frame) + FCS_SIZE); ++} ++ ++static int send_disc(ts0710_con * ts0710, __u8 dlci) ++{ ++ __u8 buf[sizeof(short_frame) + FCS_SIZE + FLAG_SIZE]; ++ short_frame *disc; ++ ++ TS0710_DEBUG("send_disc: Creating DISC packet to DLCI %d\n", dlci); ++ ++ disc = (short_frame *) (buf + 1); ++ disc->h.addr.ea = 1; ++ disc->h.addr.cr = ((ts0710->initiator) & 0x1); ++ disc->h.addr.d = dlci & 0x1; ++ disc->h.addr.server_chn = dlci >> 0x1; ++ disc->h.control = SET_PF(DISC); ++ disc->h.length.ea = 1; ++ disc->h.length.len = 0; ++ disc->data[0] = crc_calc((__u8 *) disc, SHORT_CRC_CHECK); ++ ++ return basic_write(ts0710, buf, sizeof(short_frame) + FCS_SIZE); ++} ++ ++static void queue_uih(mux_send_struct * send_info, __u16 len, ++ ts0710_con * ts0710, __u8 dlci) ++{ ++ __u32 size; ++ ++ TS0710_DEBUG ++ ("queue_uih: Creating UIH packet with %d bytes data to DLCI %d\n", ++ len, dlci); ++ ++ if (len > SHORT_PAYLOAD_SIZE) { ++ long_frame *l_pkt; ++ ++ size = sizeof(long_frame) + len + FCS_SIZE; ++ l_pkt = (long_frame *) (send_info->frame - sizeof(long_frame)); ++ set_uih_hdr((void *)l_pkt, dlci, len, ts0710->initiator); ++ l_pkt->data[len] = crc_calc((__u8 *) l_pkt, LONG_CRC_CHECK); ++ send_info->frame = ((__u8 *) l_pkt) - 1; ++ } else { ++ short_frame *s_pkt; ++ ++ size = sizeof(short_frame) + len + FCS_SIZE; ++ s_pkt = ++ (short_frame *) (send_info->frame - sizeof(short_frame)); ++ set_uih_hdr((void *)s_pkt, dlci, len, ts0710->initiator); ++ s_pkt->data[len] = crc_calc((__u8 *) s_pkt, SHORT_CRC_CHECK); ++ send_info->frame = ((__u8 *) s_pkt) - 1; ++ } ++ send_info->length = size; ++} ++ ++/* Multiplexer command packets functions */ ++ ++/* Turns on the ts0710 flow control */ ++ ++static int ts0710_fcon_msg(ts0710_con * ts0710, __u8 cr) ++{ ++ __u8 buf[30]; ++ mcc_short_frame *mcc_pkt; ++ short_frame *uih_pkt; ++ __u32 size; ++ ++ size = sizeof(short_frame) + sizeof(mcc_short_frame) + FCS_SIZE; ++ uih_pkt = (short_frame *) (buf + 1); ++ set_uih_hdr(uih_pkt, CTRL_CHAN, sizeof(mcc_short_frame), ++ ts0710->initiator); ++ uih_pkt->data[sizeof(mcc_short_frame)] = ++ crc_calc((__u8 *) uih_pkt, SHORT_CRC_CHECK); ++ mcc_pkt = (mcc_short_frame *) (uih_pkt->data); ++ ++ mcc_pkt->h.type.ea = EA; ++ mcc_pkt->h.type.cr = cr; ++ mcc_pkt->h.type.type = FCON; ++ mcc_pkt->h.length.ea = EA; ++ mcc_pkt->h.length.len = 0; ++ ++ return basic_write(ts0710, buf, size); ++} ++ ++/* Turns off the ts0710 flow control */ ++ ++static int ts0710_fcoff_msg(ts0710_con * ts0710, __u8 cr) ++{ ++ __u8 buf[30]; ++ mcc_short_frame *mcc_pkt; ++ short_frame *uih_pkt; ++ __u32 size; ++ ++ size = (sizeof(short_frame) + sizeof(mcc_short_frame) + FCS_SIZE); ++ uih_pkt = (short_frame *) (buf + 1); ++ set_uih_hdr(uih_pkt, CTRL_CHAN, sizeof(mcc_short_frame), ++ ts0710->initiator); ++ uih_pkt->data[sizeof(mcc_short_frame)] = ++ crc_calc((__u8 *) uih_pkt, SHORT_CRC_CHECK); ++ mcc_pkt = (mcc_short_frame *) (uih_pkt->data); ++ ++ mcc_pkt->h.type.ea = 1; ++ mcc_pkt->h.type.cr = cr; ++ mcc_pkt->h.type.type = FCOFF; ++ mcc_pkt->h.length.ea = 1; ++ mcc_pkt->h.length.len = 0; ++ ++ return basic_write(ts0710, buf, size); ++} ++ ++/* ++static int ts0710_rpn_msg(ts0710_con *ts0710, __u8 cr, __u8 dlci, __u8 req) ++{ ++ char buf[100]; ++ rpn_msg* rpn_pkt; ++ __u32 fsize; ++ __u32 psize; ++ ++ fsize = sizeof(rpn_msg); ++ ++ if (req) { ++ fsize -= sizeof(rpn_values); ++ } ++ ++ psize = (fsize - sizeof(short_frame) - FCS_SIZE); ++ ++ rpn_pkt = (rpn_msg *) buf; ++ ++ set_uih_hdr((short_frame *) rpn_pkt, CTRL_CHAN, psize, ts0710->initiator); ++ ++ rpn_pkt->fcs = crc_calc((__u8*) rpn_pkt, SHORT_CRC_CHECK); ++ ++ rpn_pkt->mcc_s_head.type.ea = EA; ++ rpn_pkt->mcc_s_head.type.cr = cr; ++ rpn_pkt->mcc_s_head.type.type = RPN; ++ rpn_pkt->mcc_s_head.length.ea = EA; ++ ++ rpn_pkt->dlci.ea = EA; ++ rpn_pkt->dlci.cr = 1; ++ rpn_pkt->dlci.d = dlci & 1; ++ rpn_pkt->dlci.server_chn = (dlci >> 1); ++ ++ if (req) { ++ rpn_pkt->mcc_s_head.length.len = 1; ++ rpn_pkt->rpn_val.bit_rate = rpn_pkt->fcs; ++ } else { ++ rpn_pkt->mcc_s_head.length.len = 8; ++ memcpy(&(rpn_pkt->rpn_val), &rpn_val, sizeof(rpn_values)); ++ } ++ return basic_write(ts0710, buf, fsize); ++} ++*/ ++/* ++static int ts0710_rls_msg(ts0710_con *ts0710, __u8 cr, __u8 dlci, __u8 err_code) ++{ ++ char buf[100]; ++ rls_msg *rls_pkt; ++ __u32 fsize; ++ __u32 psize; ++ ++ fsize = sizeof(rls_msg); ++ psize = fsize - sizeof(short_frame) - FCS_SIZE; ++ rls_pkt = (rls_msg *) buf; ++ ++ set_uih_hdr((short_frame *) rls_pkt, CTRL_CHAN, psize, ts0710->initiator); ++ rls_pkt->fcs = crc_calc((__u8*) rls_pkt, SHORT_CRC_CHECK); ++ ++ rls_pkt->mcc_s_head.type.ea = EA; ++ rls_pkt->mcc_s_head.type.cr = cr; ++ rls_pkt->mcc_s_head.type.type = RLS; ++ rls_pkt->mcc_s_head.length.ea = EA; ++ rls_pkt->mcc_s_head.length.len = 2; ++ ++ rls_pkt->dlci.ea = EA; ++ rls_pkt->dlci.cr = 1; ++ rls_pkt->dlci.d = dlci & 1; ++ rls_pkt->dlci.server_chn = dlci >> 1; ++ rls_pkt->error = err_code; ++ rls_pkt->res = 0; ++ ++ return basic_write(ts0710, buf, fsize); ++} ++*/ ++ ++/* Sends an PN-messages and sets the not negotiable parameters to their ++ default values in ts0710 */ ++ ++static int send_pn_msg(ts0710_con * ts0710, __u8 prior, __u32 frame_size, ++ __u8 credit_flow, __u8 credits, __u8 dlci, __u8 cr) ++{ ++ __u8 buf[30]; ++ pn_msg *pn_pkt; ++ __u32 size; ++ TS0710_DEBUG ++ ("send_pn_msg: DLCI 0x%02x, prior:0x%02x, frame_size:%d, credit_flow:%x, credits:%d, cr:%x\n", ++ dlci, prior, frame_size, credit_flow, credits, cr); ++ ++ size = sizeof(pn_msg); ++ pn_pkt = (pn_msg *) (buf + 1); ++ ++ set_uih_hdr((void *)pn_pkt, CTRL_CHAN, ++ size - (sizeof(short_frame) + FCS_SIZE), ts0710->initiator); ++ pn_pkt->fcs = crc_calc((__u8 *) pn_pkt, SHORT_CRC_CHECK); ++ ++ pn_pkt->mcc_s_head.type.ea = 1; ++ pn_pkt->mcc_s_head.type.cr = cr; ++ pn_pkt->mcc_s_head.type.type = PN; ++ pn_pkt->mcc_s_head.length.ea = 1; ++ pn_pkt->mcc_s_head.length.len = 8; ++ ++ pn_pkt->res1 = 0; ++ pn_pkt->res2 = 0; ++ pn_pkt->dlci = dlci; ++ pn_pkt->frame_type = 0; ++ pn_pkt->credit_flow = credit_flow; ++ pn_pkt->prior = prior; ++ pn_pkt->ack_timer = 0; ++ SET_PN_MSG_FRAME_SIZE(pn_pkt, frame_size); ++ pn_pkt->credits = credits; ++ pn_pkt->max_nbrof_retrans = 0; ++ ++ return basic_write(ts0710, buf, size); ++} ++ ++/* Send a Not supported command - command, which needs 3 bytes */ ++ ++static int send_nsc_msg(ts0710_con * ts0710, mcc_type cmd, __u8 cr) ++{ ++ __u8 buf[30]; ++ nsc_msg *nsc_pkt; ++ __u32 size; ++ ++ size = sizeof(nsc_msg); ++ nsc_pkt = (nsc_msg *) (buf + 1); ++ ++ set_uih_hdr((void *)nsc_pkt, CTRL_CHAN, ++ sizeof(nsc_msg) - sizeof(short_frame) - FCS_SIZE, ++ ts0710->initiator); ++ ++ nsc_pkt->fcs = crc_calc((__u8 *) nsc_pkt, SHORT_CRC_CHECK); ++ ++ nsc_pkt->mcc_s_head.type.ea = 1; ++ nsc_pkt->mcc_s_head.type.cr = cr; ++ nsc_pkt->mcc_s_head.type.type = NSC; ++ nsc_pkt->mcc_s_head.length.ea = 1; ++ nsc_pkt->mcc_s_head.length.len = 1; ++ ++ nsc_pkt->command_type.ea = 1; ++ nsc_pkt->command_type.cr = cmd.cr; ++ nsc_pkt->command_type.type = cmd.type; ++ ++ return basic_write(ts0710, buf, size); ++} ++ ++static int ts0710_msc_msg(ts0710_con * ts0710, __u8 value, __u8 cr, __u8 dlci) ++{ ++ __u8 buf[30]; ++ msc_msg *msc_pkt; ++ __u32 size; ++ ++ size = sizeof(msc_msg); ++ msc_pkt = (msc_msg *) (buf + 1); ++ ++ set_uih_hdr((void *)msc_pkt, CTRL_CHAN, ++ sizeof(msc_msg) - sizeof(short_frame) - FCS_SIZE, ++ ts0710->initiator); ++ ++ msc_pkt->fcs = crc_calc((__u8 *) msc_pkt, SHORT_CRC_CHECK); ++ ++ msc_pkt->mcc_s_head.type.ea = 1; ++ msc_pkt->mcc_s_head.type.cr = cr; ++ msc_pkt->mcc_s_head.type.type = MSC; ++ msc_pkt->mcc_s_head.length.ea = 1; ++ msc_pkt->mcc_s_head.length.len = 2; ++ ++ msc_pkt->dlci.ea = 1; ++ msc_pkt->dlci.cr = 1; ++ msc_pkt->dlci.d = dlci & 1; ++ msc_pkt->dlci.server_chn = (dlci >> 1) & 0x1f; ++ ++ msc_pkt->v24_sigs = value; ++ ++ return basic_write(ts0710, buf, size); ++} ++ ++static int ts0710_test_msg(ts0710_con * ts0710, __u8 * test_pattern, __u32 len, ++ __u8 cr, __u8 * f_buf /*Frame buf */ ) ++{ ++ __u32 size; ++ ++ if (len > SHORT_PAYLOAD_SIZE) { ++ long_frame *uih_pkt; ++ mcc_long_frame *mcc_pkt; ++ ++ size = ++ (sizeof(long_frame) + sizeof(mcc_long_frame) + len + ++ FCS_SIZE); ++ uih_pkt = (long_frame *) (f_buf + 1); ++ ++ set_uih_hdr((short_frame *) uih_pkt, CTRL_CHAN, len + ++ sizeof(mcc_long_frame), ts0710->initiator); ++ uih_pkt->data[GET_LONG_LENGTH(uih_pkt->h.length)] = ++ crc_calc((__u8 *) uih_pkt, LONG_CRC_CHECK); ++ mcc_pkt = (mcc_long_frame *) uih_pkt->data; ++ ++ mcc_pkt->h.type.ea = EA; ++ /* cr tells whether it is a commmand (1) or a response (0) */ ++ mcc_pkt->h.type.cr = cr; ++ mcc_pkt->h.type.type = TEST; ++ SET_LONG_LENGTH(mcc_pkt->h.length, len); ++ memcpy(mcc_pkt->value, test_pattern, len); ++ } else if (len > (SHORT_PAYLOAD_SIZE - sizeof(mcc_short_frame))) { ++ long_frame *uih_pkt; ++ mcc_short_frame *mcc_pkt; ++ ++ /* Create long uih packet and short mcc packet */ ++ size = ++ (sizeof(long_frame) + sizeof(mcc_short_frame) + len + ++ FCS_SIZE); ++ uih_pkt = (long_frame *) (f_buf + 1); ++ ++ set_uih_hdr((short_frame *) uih_pkt, CTRL_CHAN, ++ len + sizeof(mcc_short_frame), ts0710->initiator); ++ uih_pkt->data[GET_LONG_LENGTH(uih_pkt->h.length)] = ++ crc_calc((__u8 *) uih_pkt, LONG_CRC_CHECK); ++ mcc_pkt = (mcc_short_frame *) uih_pkt->data; ++ ++ mcc_pkt->h.type.ea = EA; ++ mcc_pkt->h.type.cr = cr; ++ mcc_pkt->h.type.type = TEST; ++ mcc_pkt->h.length.ea = EA; ++ mcc_pkt->h.length.len = len; ++ memcpy(mcc_pkt->value, test_pattern, len); ++ } else { ++ short_frame *uih_pkt; ++ mcc_short_frame *mcc_pkt; ++ ++ size = ++ (sizeof(short_frame) + sizeof(mcc_short_frame) + len + ++ FCS_SIZE); ++ uih_pkt = (short_frame *) (f_buf + 1); ++ ++ set_uih_hdr((void *)uih_pkt, CTRL_CHAN, len ++ + sizeof(mcc_short_frame), ts0710->initiator); ++ uih_pkt->data[uih_pkt->h.length.len] = ++ crc_calc((__u8 *) uih_pkt, SHORT_CRC_CHECK); ++ mcc_pkt = (mcc_short_frame *) uih_pkt->data; ++ ++ mcc_pkt->h.type.ea = EA; ++ mcc_pkt->h.type.cr = cr; ++ mcc_pkt->h.type.type = TEST; ++ mcc_pkt->h.length.ea = EA; ++ mcc_pkt->h.length.len = len; ++ memcpy(mcc_pkt->value, test_pattern, len); ++ ++ } ++ return basic_write(ts0710, f_buf, size); ++} ++ ++static void set_uih_hdr(short_frame * uih_pkt, __u8 dlci, __u32 len, __u8 cr) ++{ ++ uih_pkt->h.addr.ea = 1; ++ uih_pkt->h.addr.cr = cr; ++ uih_pkt->h.addr.d = dlci & 0x1; ++ uih_pkt->h.addr.server_chn = dlci >> 1; ++ uih_pkt->h.control = CLR_PF(UIH); ++ ++ if (len > SHORT_PAYLOAD_SIZE) { ++ SET_LONG_LENGTH(((long_frame *) uih_pkt)->h.length, len); ++ } else { ++ uih_pkt->h.length.ea = 1; ++ uih_pkt->h.length.len = len; ++ } ++} ++ ++/* Parses a multiplexer control channel packet */ ++ ++void process_mcc(__u8 * data, __u32 len, ts0710_con * ts0710, int longpkt) ++{ ++ __u8 *tbuf = NULL; ++ mcc_short_frame *mcc_short_pkt; ++ int j; ++ ++ if (longpkt) { ++ mcc_short_pkt = ++ (mcc_short_frame *) (((long_frame *) data)->data); ++ } else { ++ mcc_short_pkt = ++ (mcc_short_frame *) (((short_frame *) data)->data); ++ } ++ ++ switch (mcc_short_pkt->h.type.type) { ++ case TEST: ++ if (mcc_short_pkt->h.type.cr == MCC_RSP) { ++ TS0710_DEBUG("Received test command response\n"); ++ ++ if (ts0710->be_testing) { ++ if ((mcc_short_pkt->h.length.ea) == 0) { ++ mcc_long_frame *mcc_long_pkt; ++ mcc_long_pkt = ++ (mcc_long_frame *) mcc_short_pkt; ++ if (GET_LONG_LENGTH ++ (mcc_long_pkt->h.length) != ++ TEST_PATTERN_SIZE) { ++ ts0710->test_errs = ++ TEST_PATTERN_SIZE; ++ TS0710_DEBUG ++ ("Err: received test pattern is %d bytes long, not expected %d\n", ++ GET_LONG_LENGTH ++ (mcc_long_pkt->h.length), ++ TEST_PATTERN_SIZE); ++ } else { ++ ts0710->test_errs = 0; ++ for (j = 0; ++ j < TEST_PATTERN_SIZE; ++ j++) { ++ if (mcc_long_pkt-> ++ value[j] != ++ (j & 0xFF)) { ++ (ts0710-> ++ test_errs)++; ++ } ++ } ++ } ++ ++ } else { ++ ++#if TEST_PATTERN_SIZE < 128 ++ if (mcc_short_pkt->h.length.len != ++ TEST_PATTERN_SIZE) { ++#endif ++ ++ ts0710->test_errs = ++ TEST_PATTERN_SIZE; ++ TS0710_DEBUG ++ ("Err: received test pattern is %d bytes long, not expected %d\n", ++ mcc_short_pkt->h.length. ++ len, TEST_PATTERN_SIZE); ++ ++#if TEST_PATTERN_SIZE < 128 ++ } else { ++ ts0710->test_errs = 0; ++ for (j = 0; ++ j < TEST_PATTERN_SIZE; ++ j++) { ++ if (mcc_short_pkt-> ++ value[j] != ++ (j & 0xFF)) { ++ (ts0710-> ++ test_errs)++; ++ } ++ } ++ } ++#endif ++ ++ } ++ ++ ts0710->be_testing = 0; /* Clear the flag */ ++ wake_up_interruptible(&ts0710->test_wait); ++ } else { ++ TS0710_DEBUG ++ ("Err: shouldn't or late to get test cmd response\n"); ++ } ++ } else { ++ tbuf = (__u8 *) kmalloc(len + 32, GFP_ATOMIC); ++ if (!tbuf) { ++ break; ++ } ++ ++ if ((mcc_short_pkt->h.length.ea) == 0) { ++ mcc_long_frame *mcc_long_pkt; ++ mcc_long_pkt = (mcc_long_frame *) mcc_short_pkt; ++ ts0710_test_msg(ts0710, mcc_long_pkt->value, ++ GET_LONG_LENGTH(mcc_long_pkt->h. ++ length), ++ MCC_RSP, tbuf); ++ } else { ++ ts0710_test_msg(ts0710, mcc_short_pkt->value, ++ mcc_short_pkt->h.length.len, ++ MCC_RSP, tbuf); ++ } ++ ++ kfree(tbuf); ++ } ++ break; ++ ++ case FCON: /*Flow control on command */ ++ TS0710_PRINTK ++ ("MUX Received Flow control(all channels) on command\n"); ++ if (mcc_short_pkt->h.type.cr == MCC_CMD) { ++ ts0710->dlci[0].state = CONNECTED; ++ ts0710_fcon_msg(ts0710, MCC_RSP); ++ mux_sched_send(); ++ } ++ break; ++ ++ case FCOFF: /*Flow control off command */ ++ TS0710_PRINTK ++ ("MUX Received Flow control(all channels) off command\n"); ++ if (mcc_short_pkt->h.type.cr == MCC_CMD) { ++ for (j = 0; j < TS0710_MAX_CHN; j++) { ++ ts0710->dlci[j].state = FLOW_STOPPED; ++ } ++ ts0710_fcoff_msg(ts0710, MCC_RSP); ++ } ++ break; ++ ++ case MSC: /*Modem status command */ ++ { ++ __u8 dlci; ++ __u8 v24_sigs; ++ ++ dlci = (mcc_short_pkt->value[0]) >> 2; ++ v24_sigs = mcc_short_pkt->value[1]; ++ ++ if ((ts0710->dlci[dlci].state != CONNECTED) ++ && (ts0710->dlci[dlci].state != FLOW_STOPPED)) { ++ send_dm(ts0710, dlci); ++ break; ++ } ++ if (mcc_short_pkt->h.type.cr == MCC_CMD) { ++ TS0710_DEBUG("Received Modem status command\n"); ++ if (v24_sigs & 2) { ++ if (ts0710->dlci[dlci].state == ++ CONNECTED) { ++ TS0710_LOG ++ ("MUX Received Flow off on dlci %d\n", ++ dlci); ++ ts0710->dlci[dlci].state = ++ FLOW_STOPPED; ++ } ++ } else { ++ if (ts0710->dlci[dlci].state == ++ FLOW_STOPPED) { ++ ts0710->dlci[dlci].state = ++ CONNECTED; ++ TS0710_LOG ++ ("MUX Received Flow on on dlci %d\n", ++ dlci); ++ mux_sched_send(); ++ } ++ } ++ ++ ts0710_msc_msg(ts0710, v24_sigs, MCC_RSP, dlci); ++/* ++ if (!(ts0710->dlci[dlci].initiated) && !(ts0710->dlci[dlci].initiator)) { ++ ts0710_msc_msg(ts0710, EA | RTR | RTC | DV, MCC_CMD, dlci); ++ ts0710->dlci[dlci].initiated = 1; ++ } ++*/ ++ } else { ++ TS0710_DEBUG ++ ("Received Modem status response\n"); ++ ++ if (v24_sigs & 2) { ++ TS0710_DEBUG("Flow stop accepted\n"); ++ } ++ } ++ break; ++ } ++ ++ /* case RPN: *//*Remote port negotiation command */ ++ ++/* { ++ __u8 dlci; ++ ++ dlci = (mcc_short_pkt->value[0]) >> 2; ++ ++ if (mcc_short_pkt->h.type.cr == MCC_CMD) { ++ if (mcc_short_pkt->h.length.len == 1) { ++ TS0710_DEBUG("Received Remote port negotiation command\n"); ++ ts0710_rpn_msg(ts0710, MCC_RSP, dlci, 0); ++ } else { ++*/ ++ /* Accept the other sides settings (accept all for now) */ ++/* TS0710_DEBUG("Received Remote port negotiation respons\n"); ++ memcpy(&rpn_val, &mcc_short_pkt->value[1], 8); ++ ts0710_rpn_msg(ts0710, MCC_RSP, dlci, 0); ++*/ ++ /* Zero the parametermask after response */ ++/* memset(&rpn_val.pm, 0, 2); ++ } ++ } ++ break; ++ } ++*/ ++/* ++ case RLS: *//*Remote line status */ ++/* { ++ __u8 dlci; ++ __u8 err_code; ++ ++ TS0710_DEBUG("Received Remote line status\n"); ++ if (mcc_short_pkt->h.type.cr == MCC_CMD) { ++ dlci = mcc_short_pkt->value[0] >> 2; ++ err_code = mcc_short_pkt->value[1]; ++ ++ ts0710_rls_msg(ts0710, MCC_RSP, dlci, err_code); ++ } ++ break; ++ } ++*/ ++ case PN: /*DLC parameter negotiation */ ++ { ++ __u8 dlci; ++ __u16 frame_size; ++ pn_msg *pn_pkt; ++ ++ pn_pkt = (pn_msg *) data; ++ dlci = pn_pkt->dlci; ++ frame_size = GET_PN_MSG_FRAME_SIZE(pn_pkt); ++ TS0710_DEBUG ++ ("Received DLC parameter negotiation, PN\n"); ++ if (pn_pkt->mcc_s_head.type.cr == MCC_CMD) { ++ TS0710_DEBUG("received PN command with:\n"); ++ TS0710_DEBUG("Frame size:%d\n", frame_size); ++ ++ frame_size = ++ min(frame_size, ts0710->dlci[dlci].mtu); ++ send_pn_msg(ts0710, pn_pkt->prior, frame_size, ++ 0, 0, dlci, MCC_RSP); ++ ts0710->dlci[dlci].mtu = frame_size; ++ TS0710_DEBUG("process_mcc : mtu set to %d\n", ++ ts0710->dlci[dlci].mtu); ++ } else { ++ TS0710_DEBUG("received PN response with:\n"); ++ TS0710_DEBUG("Frame size:%d\n", frame_size); ++ ++ frame_size = ++ min(frame_size, ts0710->dlci[dlci].mtu); ++ ts0710->dlci[dlci].mtu = frame_size; ++ ++ TS0710_DEBUG ++ ("process_mcc : mtu set on dlci:%d to %d\n", ++ dlci, ts0710->dlci[dlci].mtu); ++ ++ if (ts0710->dlci[dlci].state == NEGOTIATING) { ++ ts0710->dlci[dlci].state = CONNECTING; ++ wake_up_interruptible(&ts0710-> ++ dlci[dlci]. ++ open_wait); ++ } ++ } ++ break; ++ } ++ ++ case NSC: /*Non supported command resonse */ ++ TS0710_LOG("MUX Received Non supported command response\n"); ++ break; ++ ++ default: /*Non supported command received */ ++ TS0710_LOG("MUX Received a non supported command\n"); ++ send_nsc_msg(ts0710, mcc_short_pkt->h.type, MCC_RSP); ++ break; ++ } ++} ++ ++static mux_recv_packet *get_mux_recv_packet(__u32 size) ++{ ++ mux_recv_packet *recv_packet; ++ ++ TS0710_DEBUG("Enter into get_mux_recv_packet"); ++ ++ recv_packet = ++ (mux_recv_packet *) kmalloc(sizeof(mux_recv_packet), GFP_ATOMIC); ++ if (!recv_packet) { ++ return 0; ++ } ++ ++ recv_packet->data = (__u8 *) kmalloc(size, GFP_ATOMIC); ++ if (!(recv_packet->data)) { ++ kfree(recv_packet); ++ return 0; ++ } ++ recv_packet->length = 0; ++ recv_packet->next = 0; ++ return recv_packet; ++} ++ ++static void free_mux_recv_packet(mux_recv_packet * recv_packet) ++{ ++ TS0710_DEBUG("Enter into free_mux_recv_packet"); ++ ++ if (!recv_packet) { ++ return; ++ } ++ ++ if (recv_packet->data) { ++ kfree(recv_packet->data); ++ } ++ kfree(recv_packet); ++} ++ ++static void free_mux_recv_struct(mux_recv_struct * recv_info) ++{ ++ mux_recv_packet *recv_packet1, *recv_packet2; ++ ++ if (!recv_info) { ++ return; ++ } ++ ++ recv_packet1 = recv_info->mux_packet; ++ while (recv_packet1) { ++ recv_packet2 = recv_packet1->next; ++ free_mux_recv_packet(recv_packet1); ++ recv_packet1 = recv_packet2; ++ } ++ ++ kfree(recv_info); ++} ++ ++static inline void add_post_recv_queue(mux_recv_struct ** head, ++ mux_recv_struct * new_item) ++{ ++ new_item->next = *head; ++ *head = new_item; ++} ++ ++static void ts0710_flow_on(__u8 dlci, ts0710_con * ts0710) ++{ ++ int i; ++ __u8 cmdtty; ++ __u8 datatty; ++ struct tty_struct *tty; ++ mux_recv_struct *recv_info; ++ ++ if ((ts0710->dlci[0].state != CONNECTED) ++ && (ts0710->dlci[0].state != FLOW_STOPPED)) { ++ return; ++ } else if ((ts0710->dlci[dlci].state != CONNECTED) ++ && (ts0710->dlci[dlci].state != FLOW_STOPPED)) { ++ return; ++ } ++ ++ if (!(ts0710->dlci[dlci].flow_control)) { ++ return; ++ } ++ ++ cmdtty = dlci2tty[dlci].cmdtty; ++ datatty = dlci2tty[dlci].datatty; ++ ++ if (cmdtty != datatty) { ++ /* Check AT cmd tty */ ++ tty = mux_table[cmdtty]; ++ if (mux_tty[cmdtty] && tty) { ++ if (test_bit(TTY_THROTTLED, &tty->flags)) { ++ return; ++ } ++ } ++ recv_info = mux_recv_info[cmdtty]; ++ if (mux_recv_info_flags[cmdtty] && recv_info) { ++ if (recv_info->total) { ++ return; ++ } ++ } ++ ++ /* Check data tty */ ++ tty = mux_table[datatty]; ++ if (mux_tty[datatty] && tty) { ++ if (test_bit(TTY_THROTTLED, &tty->flags)) { ++ return; ++ } ++ } ++ recv_info = mux_recv_info[datatty]; ++ if (mux_recv_info_flags[datatty] && recv_info) { ++ if (recv_info->total) { ++ return; ++ } ++ } ++ } ++ ++ for (i = 0; i < 3; i++) { ++ if (ts0710_msc_msg(ts0710, EA | RTC | RTR | DV, MCC_CMD, dlci) < ++ 0) { ++ continue; ++ } else { ++ TS0710_LOG("MUX send Flow on on dlci %d\n", dlci); ++ ts0710->dlci[dlci].flow_control = 0; ++ break; ++ } ++ } ++} ++ ++static void ts0710_flow_off(struct tty_struct *tty, __u8 dlci, ++ ts0710_con * ts0710) ++{ ++ int i; ++ ++ if (test_and_set_bit(TTY_THROTTLED, &tty->flags)) { ++ return; ++ } ++ ++ if ((ts0710->dlci[0].state != CONNECTED) ++ && (ts0710->dlci[0].state != FLOW_STOPPED)) { ++ return; ++ } else if ((ts0710->dlci[dlci].state != CONNECTED) ++ && (ts0710->dlci[dlci].state != FLOW_STOPPED)) { ++ return; ++ } ++ ++ if (ts0710->dlci[dlci].flow_control) { ++ return; ++ } ++ ++ for (i = 0; i < 3; i++) { ++ if (ts0710_msc_msg ++ (ts0710, EA | FC | RTC | RTR | DV, MCC_CMD, dlci) < 0) { ++ continue; ++ } else { ++ TS0710_LOG("MUX send Flow off on dlci %d\n", dlci); ++ ts0710->dlci[dlci].flow_control = 1; ++ break; ++ } ++ } ++} ++ ++int ts0710_recv_data(ts0710_con * ts0710, char *data, int len) ++{ ++ short_frame *short_pkt; ++ long_frame *long_pkt; ++ __u8 *uih_data_start; ++ __u32 uih_len; ++ __u8 dlci; ++ __u8 be_connecting; ++#ifdef TS0710DEBUG ++ unsigned long t; ++#endif ++ ++ short_pkt = (short_frame *) data; ++ ++ dlci = short_pkt->h.addr.server_chn << 1 | short_pkt->h.addr.d; ++ switch (CLR_PF(short_pkt->h.control)) { ++ case SABM: ++ TS0710_DEBUG("SABM-packet received\n"); ++ ++/*For BP UART problem ++ if( crc_check((__u8*) short_pkt, SHORT_CRC_CHECK, short_pkt->data[0]) ) ++ break; ++*/ ++ ++ if (!dlci) { ++ TS0710_DEBUG("server channel == 0\n"); ++ ts0710->dlci[0].state = CONNECTED; ++ ++ TS0710_DEBUG("sending back UA - control channel\n"); ++ send_ua(ts0710, dlci); ++ wake_up_interruptible(&ts0710->dlci[0].open_wait); ++ ++ } else if (valid_dlci(dlci)) { ++ ++ TS0710_DEBUG("Incomming connect on channel %d\n", dlci); ++ ++ TS0710_DEBUG("sending UA, dlci %d\n", dlci); ++ send_ua(ts0710, dlci); ++ ++ ts0710->dlci[dlci].state = CONNECTED; ++ wake_up_interruptible(&ts0710->dlci[dlci].open_wait); ++ ++ } else { ++ TS0710_DEBUG("invalid dlci %d, sending DM\n", dlci); ++ send_dm(ts0710, dlci); ++ } ++ ++ break; ++ ++ case UA: ++ TS0710_DEBUG("UA packet received\n"); ++ ++/*For BP UART problem ++ if( crc_check((__u8*) short_pkt, SHORT_CRC_CHECK, short_pkt->data[0]) ) ++ break; ++*/ ++ ++ if (!dlci) { ++ TS0710_DEBUG("server channel == 0\n"); ++ ++ if (ts0710->dlci[0].state == CONNECTING) { ++ ts0710->dlci[0].state = CONNECTED; ++ wake_up_interruptible(&ts0710->dlci[0]. ++ open_wait); ++ } else if (ts0710->dlci[0].state == DISCONNECTING) { ++ ts0710_upon_disconnect(); ++ } else { ++ TS0710_DEBUG ++ (" Something wrong receiving UA packet\n"); ++ } ++ } else if (valid_dlci(dlci)) { ++ TS0710_DEBUG("Incomming UA on channel %d\n", dlci); ++ ++ if (ts0710->dlci[dlci].state == CONNECTING) { ++ ts0710->dlci[dlci].state = CONNECTED; ++ wake_up_interruptible(&ts0710->dlci[dlci]. ++ open_wait); ++ } else if (ts0710->dlci[dlci].state == DISCONNECTING) { ++ ts0710->dlci[dlci].state = DISCONNECTED; ++ wake_up_interruptible(&ts0710->dlci[dlci]. ++ open_wait); ++ wake_up_interruptible(&ts0710->dlci[dlci]. ++ close_wait); ++ ts0710_reset_dlci(dlci); ++ } else { ++ TS0710_DEBUG ++ (" Something wrong receiving UA packet\n"); ++ } ++ } else { ++ TS0710_DEBUG("invalid dlci %d\n", dlci); ++ } ++ ++ break; ++ ++ case DM: ++ TS0710_DEBUG("DM packet received\n"); ++ ++/*For BP UART problem ++ if( crc_check((__u8*) short_pkt, SHORT_CRC_CHECK, short_pkt->data[0]) ) ++ break; ++*/ ++ ++ if (!dlci) { ++ TS0710_DEBUG("server channel == 0\n"); ++ ++ if (ts0710->dlci[0].state == CONNECTING) { ++ be_connecting = 1; ++ } else { ++ be_connecting = 0; ++ } ++ ts0710_upon_disconnect(); ++ if (be_connecting) { ++ ts0710->dlci[0].state = REJECTED; ++ } ++ } else if (valid_dlci(dlci)) { ++ TS0710_DEBUG("Incomming DM on channel %d\n", dlci); ++ ++ if (ts0710->dlci[dlci].state == CONNECTING) { ++ ts0710->dlci[dlci].state = REJECTED; ++ } else { ++ ts0710->dlci[dlci].state = DISCONNECTED; ++ } ++ wake_up_interruptible(&ts0710->dlci[dlci].open_wait); ++ wake_up_interruptible(&ts0710->dlci[dlci].close_wait); ++ ts0710_reset_dlci(dlci); ++ } else { ++ TS0710_DEBUG("invalid dlci %d\n", dlci); ++ } ++ ++ break; ++ ++ case DISC: ++ TS0710_DEBUG("DISC packet received\n"); ++ ++/*For BP UART problem ++ if( crc_check((__u8*) short_pkt, SHORT_CRC_CHECK, short_pkt->data[0]) ) ++ break; ++*/ ++ ++ if (!dlci) { ++ TS0710_DEBUG("server channel == 0\n"); ++ ++ send_ua(ts0710, dlci); ++ TS0710_DEBUG("DISC, sending back UA\n"); ++ ++ ts0710_upon_disconnect(); ++ } else if (valid_dlci(dlci)) { ++ TS0710_DEBUG("Incomming DISC on channel %d\n", dlci); ++ ++ send_ua(ts0710, dlci); ++ TS0710_DEBUG("DISC, sending back UA\n"); ++ ++ ts0710->dlci[dlci].state = DISCONNECTED; ++ wake_up_interruptible(&ts0710->dlci[dlci].open_wait); ++ wake_up_interruptible(&ts0710->dlci[dlci].close_wait); ++ ts0710_reset_dlci(dlci); ++ } else { ++ TS0710_DEBUG("invalid dlci %d\n", dlci); ++ } ++ ++ break; ++ ++ case UIH: ++ TS0710_DEBUG("UIH packet received\n"); ++ ++ if ((dlci >= TS0710_MAX_CHN)) { ++ TS0710_DEBUG("invalid dlci %d\n", dlci); ++ send_dm(ts0710, dlci); ++ break; ++ } ++ ++ if (GET_PF(short_pkt->h.control)) { ++ TS0710_LOG ++ ("MUX Error %s: UIH packet with P/F set, discard it!\n", ++ __FUNCTION__); ++ break; ++ } ++ ++ if ((ts0710->dlci[dlci].state != CONNECTED) ++ && (ts0710->dlci[dlci].state != FLOW_STOPPED)) { ++ TS0710_LOG ++ ("MUX Error %s: DLCI %d not connected, discard it!\n", ++ __FUNCTION__, dlci); ++ send_dm(ts0710, dlci); ++ break; ++ } ++ ++ if ((short_pkt->h.length.ea) == 0) { ++ TS0710_DEBUG("Long UIH packet received\n"); ++ long_pkt = (long_frame *) data; ++ uih_len = GET_LONG_LENGTH(long_pkt->h.length); ++ uih_data_start = long_pkt->h.data; ++ TS0710_DEBUG("long packet length %d\n", uih_len); ++ ++/*For BP UART problem ++ if (crc_check(data, LONG_CRC_CHECK, *(uih_data_start + uih_len))) ++ break; ++*/ ++ } else { ++ TS0710_DEBUG("Short UIH pkt received\n"); ++ uih_len = short_pkt->h.length.len; ++ uih_data_start = short_pkt->data; ++ ++/*For BP UART problem ++ if (crc_check(data, SHORT_CRC_CHECK, *(uih_data_start + uih_len))) ++ break; ++*/ ++ } ++ ++ if (dlci == 0) { ++ TS0710_DEBUG("UIH on serv_channel 0\n"); ++ process_mcc(data, len, ts0710, ++ !(short_pkt->h.length.ea)); ++ } else if (valid_dlci(dlci)) { ++ /* do tty dispatch */ ++ __u8 tag; ++ __u8 tty_idx; ++ struct tty_struct *tty; ++ __u8 queue_data; ++ __u8 post_recv; ++ __u8 flow_control; ++ mux_recv_struct *recv_info; ++ int recv_room; ++ mux_recv_packet *recv_packet, *recv_packet2; ++ ++ TS0710_DEBUG("UIH on channel %d\n", dlci); ++ ++ if (uih_len > ts0710->dlci[dlci].mtu) { ++ TS0710_PRINTK ++ ("MUX Error: DLCI:%d, uih_len:%d is bigger than mtu:%d, discard data!\n", ++ dlci, uih_len, ts0710->dlci[dlci].mtu); ++ break; ++ } ++ ++ tag = *uih_data_start; ++ uih_data_start++; ++ uih_len--; ++ ++ if (!uih_len) { ++ break; ++ } ++ ++ switch (tag) { ++ case CMDTAG: ++ tty_idx = dlci2tty[dlci].cmdtty; ++ TS0710_DEBUG("CMDTAG on DLCI:%d, /dev/mux%d\n", ++ dlci, tty_idx); ++ TS0710_DEBUGSTR(uih_data_start, uih_len); ++ if (!(iscmdtty[tty_idx])) { ++ TS0710_PRINTK ++ ("MUX Error: %s: Wrong CMDTAG on DLCI:%d, /dev/mux%d\n", ++ __FUNCTION__, dlci, tty_idx); ++ } ++ break; ++ case DATATAG: ++ default: ++ tty_idx = dlci2tty[dlci].datatty; ++ TS0710_DEBUG ++ ("NON-CMDTAG on DLCI:%d, /dev/mux%d\n", ++ dlci, tty_idx); ++ if (iscmdtty[tty_idx]) { ++ TS0710_PRINTK ++ ("MUX Error: %s: Wrong NON-CMDTAG on DLCI:%d, /dev/mux%d\n", ++ __FUNCTION__, dlci, tty_idx); ++ } ++ break; ++ } ++ tty = mux_table[tty_idx]; ++ if ((!mux_tty[tty_idx]) || (!tty)) { ++ TS0710_PRINTK ++ ("MUX: No application waiting for, discard it! /dev/mux%d\n", ++ tty_idx); ++ } else { /* Begin processing received data */ ++ if ((!mux_recv_info_flags[tty_idx]) ++ || (!mux_recv_info[tty_idx])) { ++ TS0710_PRINTK ++ ("MUX Error: No mux_recv_info, discard it! /dev/mux%d\n", ++ tty_idx); ++ break; ++ } ++ ++ recv_info = mux_recv_info[tty_idx]; ++ if (recv_info->total > 8192) { ++ TS0710_PRINTK ++ ("MUX : discard data for tty_idx:%d, recv_info->total > 8192 \n", ++ tty_idx); ++ break; ++ } ++ ++ queue_data = 0; ++ post_recv = 0; ++ flow_control = 0; ++ recv_room = 65535; ++ if (tty->receive_room) ++ recv_room = tty->receive_room; ++ ++ if (test_bit(TTY_THROTTLED, &tty->flags)) { ++ queue_data = 1; ++ } else { ++ if (test_bit ++ (TTY_DONT_FLIP, &tty->flags)) { ++ queue_data = 1; ++ post_recv = 1; ++ } else if (recv_info->total) { ++ queue_data = 1; ++ post_recv = 1; ++ } else if (recv_room < uih_len) { ++ queue_data = 1; ++ flow_control = 1; ++ } ++ ++ if ((recv_room - ++ (uih_len + recv_info->total)) < ++ ts0710->dlci[dlci].mtu) { ++ flow_control = 1; ++ } ++ } ++ ++ if (!queue_data) { ++ /* Put received data into read buffer of tty */ ++ TS0710_DEBUG ++ ("Put received data into read buffer of /dev/mux%d", ++ tty_idx); ++ ++#ifdef TS0710DEBUG ++ t = jiffies; ++#endif ++ ++ (tty->ldisc.receive_buf) (tty, ++ uih_data_start, ++ NULL, ++ uih_len); ++ ++#ifdef TS0710DEBUG ++ TS0710_DEBUG ++ ("tty->ldisc.receive_buf take ticks: %lu", ++ (jiffies - t)); ++#endif ++ ++ } else { /* Queue data */ ++ ++ TS0710_DEBUG ++ ("Put received data into recv queue of /dev/mux%d", ++ tty_idx); ++ if (recv_info->total) { ++ /* recv_info is already linked into mux_recv_queue */ ++ ++ recv_packet = ++ get_mux_recv_packet ++ (uih_len); ++ if (!recv_packet) { ++ TS0710_PRINTK ++ ("MUX %s: no memory\n", ++ __FUNCTION__); ++ break; ++ } ++ ++ memcpy(recv_packet->data, ++ uih_data_start, uih_len); ++ recv_packet->length = uih_len; ++ recv_info->total += uih_len; ++ recv_packet->next = NULL; ++ ++ if (!(recv_info->mux_packet)) { ++ recv_info->mux_packet = ++ recv_packet; ++ } else { ++ recv_packet2 = ++ recv_info-> ++ mux_packet; ++ while (recv_packet2-> ++ next) { ++ recv_packet2 = ++ recv_packet2-> ++ next; ++ } ++ recv_packet2->next = ++ recv_packet; ++ } /* End if( !(recv_info->mux_packet) ) */ ++ } else { /* recv_info->total == 0 */ ++ if (uih_len > ++ TS0710MUX_RECV_BUF_SIZE) { ++ TS0710_PRINTK ++ ("MUX Error: tty_idx:%d, uih_len == %d is too big\n", ++ tty_idx, uih_len); ++ uih_len = ++ TS0710MUX_RECV_BUF_SIZE; ++ } ++ memcpy(recv_info->data, ++ uih_data_start, uih_len); ++ recv_info->length = uih_len; ++ recv_info->total = uih_len; ++ ++ add_post_recv_queue ++ (&mux_recv_queue, ++ recv_info); ++ } /* End recv_info->total == 0 */ ++ } /* End Queue data */ ++ ++ if (flow_control) { ++ /* Do something for flow control */ ++ ts0710_flow_off(tty, dlci, ts0710); ++ } ++ ++ if (tty_idx == ++ dlci2tty[TS0710MUX_GPRS1_DLCI].datatty) { ++ if (add_count ++ (TS0710MUX_GPRS1_RECV_COUNT_IDX, ++ uih_len) < 0) { ++ post_recv_count_flag = 1; ++ post_recv = 1; ++ mux_data_count2 ++ [TS0710MUX_GPRS1_RECV_COUNT_IDX] ++ += uih_len; ++ } ++ } else if (tty_idx == ++ dlci2tty[TS0710MUX_GPRS2_DLCI]. ++ datatty) { ++ if (add_count ++ (TS0710MUX_GPRS2_RECV_COUNT_IDX, ++ uih_len) < 0) { ++ post_recv_count_flag = 1; ++ post_recv = 1; ++ mux_data_count2 ++ [TS0710MUX_GPRS2_RECV_COUNT_IDX] ++ += uih_len; ++ } ++ } ++ ++ if (post_recv) ++ schedule_work(&post_recv_tqueue); ++ } /* End processing received data */ ++ } else { ++ TS0710_DEBUG("invalid dlci %d\n", dlci); ++ } ++ ++ break; ++ ++ default: ++ TS0710_DEBUG("illegal packet\n"); ++ break; ++ } ++ return 0; ++} ++ ++/* ++int ts0710_send_data(ts0710_con *ts0710, __u8 dlci, __u8 *data, __u32 count) ++{ ++ __u32 c, total = 0; ++ __u8 tag, first; ++ ++ if( ts0710->dlci[0].state == FLOW_STOPPED ){ ++ TS0710_DEBUG("Flow stopped on all channels, returning zero\n"); ++*/ ++/* ++ return -EFLOWSTOPPED; ++ } else if( ts0710->dlci[dlci].state == FLOW_STOPPED ){ ++ TS0710_DEBUG("Flow stopped, returning zero\n"); ++*/ ++/* ++ return -EFLOWSTOPPED; ++ } else if( ts0710->dlci[dlci].state == CONNECTED ){ ++ ++ TS0710_DEBUG("trying to send %d bytes\n", count); ++ tag = *data; ++ first = 1; ++*/ ++ /* The first byte is always a Cmd/Data tag */ ++/* ++ while( count > 1 ){ ++ ++ c = min(count, ts0710->dlci[dlci].mtu); ++ if( queue_uih(data, c, ts0710, dlci) <= 0 ) { ++ break; ++ } ++ ++ total += (c - 1); ++ data += (c - 1); ++ *data = tag; ++ count -= (c - 1); ++ ++ if( first ) { ++ first = 0; ++ total++; ++ } ++ } ++ TS0710_DEBUG("sent %d bytes\n", total); ++ return total; ++ } else { ++ TS0710_DEBUG("DLCI %d not connected\n", dlci); ++ return -EDISCONNECTED; ++ } ++} ++*/ ++ ++/* Close ts0710 channel */ ++static void ts0710_close_channel(__u8 dlci) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ int try; ++ unsigned long t; ++ ++ TS0710_DEBUG("ts0710_disc_command on channel %d\n", dlci); ++ ++ if ((ts0710->dlci[dlci].state == DISCONNECTED) ++ || (ts0710->dlci[dlci].state == REJECTED)) { ++ return; ++ } else if (ts0710->dlci[dlci].state == DISCONNECTING) { ++ /* Reentry */ ++ return; ++ } else { ++ ts0710->dlci[dlci].state = DISCONNECTING; ++ try = 3; ++ while (try--) { ++ t = jiffies; ++ send_disc(ts0710, dlci); ++ interruptible_sleep_on_timeout(&ts0710->dlci[dlci]. ++ close_wait, ++ TS0710MUX_TIME_OUT); ++ if (ts0710->dlci[dlci].state == DISCONNECTED) { ++ break; ++ } else if (signal_pending(current)) { ++ TS0710_PRINTK ++ ("MUX DLCI %d Send DISC got signal!\n", ++ dlci); ++ break; ++ } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) { ++ TS0710_PRINTK ++ ("MUX DLCI %d Send DISC timeout!\n", dlci); ++ continue; ++ } ++ } ++ ++ if (ts0710->dlci[dlci].state != DISCONNECTED) { ++ if (dlci == 0) { /* Control Channel */ ++ ts0710_upon_disconnect(); ++ } else { /* Other Channel */ ++ ts0710->dlci[dlci].state = DISCONNECTED; ++ wake_up_interruptible(&ts0710->dlci[dlci]. ++ close_wait); ++ ts0710_reset_dlci(dlci); ++ } ++ } ++ } ++} ++ ++int ts0710_open_channel(__u8 dlci) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ int try; ++ int retval; ++ unsigned long t; ++ ++ retval = -ENODEV; ++ if (dlci == 0) { // control channel ++ if ((ts0710->dlci[0].state == CONNECTED) ++ || (ts0710->dlci[0].state == FLOW_STOPPED)) { ++ return 0; ++ } else if (ts0710->dlci[0].state == CONNECTING) { ++ /* Reentry */ ++ TS0710_PRINTK ++ ("MUX DLCI: 0, reentry to open DLCI 0, pid: %d, %s !\n", ++ current->pid, current->comm); ++ try = 11; ++ while (try--) { ++ t = jiffies; ++ interruptible_sleep_on_timeout(&ts0710->dlci[0]. ++ open_wait, ++ TS0710MUX_TIME_OUT); ++ if ((ts0710->dlci[0].state == CONNECTED) ++ || (ts0710->dlci[0].state == ++ FLOW_STOPPED)) { ++ retval = 0; ++ break; ++ } else if (ts0710->dlci[0].state == REJECTED) { ++ retval = -EREJECTED; ++ break; ++ } else if (ts0710->dlci[0].state == ++ DISCONNECTED) { ++ break; ++ } else if (signal_pending(current)) { ++ TS0710_PRINTK ++ ("MUX DLCI:%d Wait for connecting got signal!\n", ++ dlci); ++ retval = -EAGAIN; ++ break; ++ } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) { ++ TS0710_PRINTK ++ ("MUX DLCI:%d Wait for connecting timeout!\n", ++ dlci); ++ continue; ++ } else if (ts0710->dlci[0].state == CONNECTING) { ++ continue; ++ } ++ } ++ ++ if (ts0710->dlci[0].state == CONNECTING) { ++ ts0710->dlci[0].state = DISCONNECTED; ++ } ++ } else if ((ts0710->dlci[0].state != DISCONNECTED) ++ && (ts0710->dlci[0].state != REJECTED)) { ++ TS0710_PRINTK("MUX DLCI:%d state is invalid!\n", dlci); ++ return retval; ++ } else { ++ ts0710->initiator = 1; ++ ts0710->dlci[0].state = CONNECTING; ++ ts0710->dlci[0].initiator = 1; ++ try = 10; ++ while (try--) { ++ t = jiffies; ++ send_sabm(ts0710, 0); ++ interruptible_sleep_on_timeout(&ts0710->dlci[0]. ++ open_wait, ++ TS0710MUX_TIME_OUT); ++ if ((ts0710->dlci[0].state == CONNECTED) ++ || (ts0710->dlci[0].state == ++ FLOW_STOPPED)) { ++ retval = 0; ++ break; ++ } else if (ts0710->dlci[0].state == REJECTED) { ++ TS0710_PRINTK ++ ("MUX DLCI:%d Send SABM got rejected!\n", ++ dlci); ++ retval = -EREJECTED; ++ break; ++ } else if (signal_pending(current)) { ++ TS0710_PRINTK ++ ("MUX DLCI:%d Send SABM got signal!\n", ++ dlci); ++ retval = -EAGAIN; ++ break; ++ } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) { ++ TS0710_PRINTK ++ ("MUX DLCI:%d Send SABM timeout!\n", ++ dlci); ++ continue; ++ } ++ } ++ ++ if (ts0710->dlci[0].state == CONNECTING) { ++ ts0710->dlci[0].state = DISCONNECTED; ++ } ++ wake_up_interruptible(&ts0710->dlci[0].open_wait); ++ } ++ } else { // other channel ++ if ((ts0710->dlci[0].state != CONNECTED) ++ && (ts0710->dlci[0].state != FLOW_STOPPED)) { ++ return retval; ++ } else if ((ts0710->dlci[dlci].state == CONNECTED) ++ || (ts0710->dlci[dlci].state == FLOW_STOPPED)) { ++ return 0; ++ } else if ((ts0710->dlci[dlci].state == NEGOTIATING) ++ || (ts0710->dlci[dlci].state == CONNECTING)) { ++ /* Reentry */ ++ try = 8; ++ while (try--) { ++ t = jiffies; ++ interruptible_sleep_on_timeout(&ts0710-> ++ dlci[dlci]. ++ open_wait, ++ TS0710MUX_TIME_OUT); ++ if ((ts0710->dlci[dlci].state == CONNECTED) ++ || (ts0710->dlci[dlci].state == ++ FLOW_STOPPED)) { ++ retval = 0; ++ break; ++ } else if (ts0710->dlci[dlci].state == REJECTED) { ++ retval = -EREJECTED; ++ break; ++ } else if (ts0710->dlci[dlci].state == ++ DISCONNECTED) { ++ break; ++ } else if (signal_pending(current)) { ++ TS0710_PRINTK ++ ("MUX DLCI:%d Wait for connecting got signal!\n", ++ dlci); ++ retval = -EAGAIN; ++ break; ++ } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) { ++ TS0710_PRINTK ++ ("MUX DLCI:%d Wait for connecting timeout!\n", ++ dlci); ++ continue; ++ } else ++ if ((ts0710->dlci[dlci].state == ++ NEGOTIATING) ++ || (ts0710->dlci[dlci].state == ++ CONNECTING)) { ++ continue; ++ } ++ } ++ ++ if ((ts0710->dlci[dlci].state == NEGOTIATING) ++ || (ts0710->dlci[dlci].state == CONNECTING)) { ++ ts0710->dlci[dlci].state = DISCONNECTED; ++ } ++ } else if ((ts0710->dlci[dlci].state != DISCONNECTED) ++ && (ts0710->dlci[dlci].state != REJECTED)) { ++ TS0710_PRINTK("MUX DLCI:%d state is invalid!\n", dlci); ++ return retval; ++ } else { ++ ts0710->dlci[dlci].state = NEGOTIATING; ++ ts0710->dlci[dlci].initiator = 1; ++ try = 3; ++ while (try--) { ++ t = jiffies; ++ send_pn_msg(ts0710, 7, ts0710->dlci[dlci].mtu, ++ 0, 0, dlci, 1); ++ interruptible_sleep_on_timeout(&ts0710-> ++ dlci[dlci]. ++ open_wait, ++ TS0710MUX_TIME_OUT); ++ if (ts0710->dlci[dlci].state == CONNECTING) { ++ break; ++ } else if (signal_pending(current)) { ++ TS0710_PRINTK ++ ("MUX DLCI:%d Send pn_msg got signal!\n", ++ dlci); ++ retval = -EAGAIN; ++ break; ++ } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) { ++ TS0710_PRINTK ++ ("MUX DLCI:%d Send pn_msg timeout!\n", ++ dlci); ++ continue; ++ } ++ } ++ ++ if (ts0710->dlci[dlci].state == CONNECTING) { ++ try = 3; ++ while (try--) { ++ t = jiffies; ++ send_sabm(ts0710, dlci); ++ interruptible_sleep_on_timeout(&ts0710-> ++ dlci ++ [dlci]. ++ open_wait, ++ TS0710MUX_TIME_OUT); ++ if ((ts0710->dlci[dlci].state == ++ CONNECTED) ++ || (ts0710->dlci[dlci].state == ++ FLOW_STOPPED)) { ++ retval = 0; ++ break; ++ } else if (ts0710->dlci[dlci].state == ++ REJECTED) { ++ TS0710_PRINTK ++ ("MUX DLCI:%d Send SABM got rejected!\n", ++ dlci); ++ retval = -EREJECTED; ++ break; ++ } else if (signal_pending(current)) { ++ TS0710_PRINTK ++ ("MUX DLCI:%d Send SABM got signal!\n", ++ dlci); ++ retval = -EAGAIN; ++ break; ++ } else if ((jiffies - t) >= ++ TS0710MUX_TIME_OUT) { ++ TS0710_PRINTK ++ ("MUX DLCI:%d Send SABM timeout!\n", ++ dlci); ++ continue; ++ } ++ } ++ } ++ ++ if ((ts0710->dlci[dlci].state == NEGOTIATING) ++ || (ts0710->dlci[dlci].state == CONNECTING)) { ++ ts0710->dlci[dlci].state = DISCONNECTED; ++ } ++ wake_up_interruptible(&ts0710->dlci[dlci].open_wait); ++ } ++ } ++ return retval; ++} ++ ++static int ts0710_exec_test_cmd(void) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ __u8 *f_buf; /* Frame buffer */ ++ __u8 *d_buf; /* Data buffer */ ++ int retval = -EFAULT; ++ int j; ++ unsigned long t; ++ ++ if (ts0710->be_testing) { ++ /* Reentry */ ++ t = jiffies; ++ interruptible_sleep_on_timeout(&ts0710->test_wait, ++ 3 * TS0710MUX_TIME_OUT); ++ if (ts0710->be_testing == 0) { ++ if (ts0710->test_errs == 0) { ++ retval = 0; ++ } else { ++ retval = -EFAULT; ++ } ++ } else if (signal_pending(current)) { ++ TS0710_DEBUG ++ ("Wait for Test_cmd response got signal!\n"); ++ retval = -EAGAIN; ++ } else if ((jiffies - t) >= 3 * TS0710MUX_TIME_OUT) { ++ TS0710_DEBUG("Wait for Test_cmd response timeout!\n"); ++ retval = -EFAULT; ++ } ++ } else { ++ ts0710->be_testing = 1; /* Set the flag */ ++ ++ f_buf = (__u8 *) kmalloc(TEST_PATTERN_SIZE + 32, GFP_KERNEL); ++ d_buf = (__u8 *) kmalloc(TEST_PATTERN_SIZE + 32, GFP_KERNEL); ++ if ((!f_buf) || (!d_buf)) { ++ if (f_buf) { ++ kfree(f_buf); ++ } ++ if (d_buf) { ++ kfree(d_buf); ++ } ++ ++ ts0710->be_testing = 0; /* Clear the flag */ ++ ts0710->test_errs = TEST_PATTERN_SIZE; ++ wake_up_interruptible(&ts0710->test_wait); ++ return -ENOMEM; ++ } ++ ++ for (j = 0; j < TEST_PATTERN_SIZE; j++) { ++ d_buf[j] = j & 0xFF; ++ } ++ ++ t = jiffies; ++ ts0710_test_msg(ts0710, d_buf, TEST_PATTERN_SIZE, MCC_CMD, ++ f_buf); ++ interruptible_sleep_on_timeout(&ts0710->test_wait, ++ 2 * TS0710MUX_TIME_OUT); ++ if (ts0710->be_testing == 0) { ++ if (ts0710->test_errs == 0) { ++ retval = 0; ++ } else { ++ retval = -EFAULT; ++ } ++ } else if (signal_pending(current)) { ++ TS0710_DEBUG("Send Test_cmd got signal!\n"); ++ retval = -EAGAIN; ++ } else if ((jiffies - t) >= 2 * TS0710MUX_TIME_OUT) { ++ TS0710_DEBUG("Send Test_cmd timeout!\n"); ++ ts0710->test_errs = TEST_PATTERN_SIZE; ++ retval = -EFAULT; ++ } ++ ++ ts0710->be_testing = 0; /* Clear the flag */ ++ wake_up_interruptible(&ts0710->test_wait); ++ ++ /* Release buffer */ ++ if (f_buf) { ++ kfree(f_buf); ++ } ++ if (d_buf) { ++ kfree(d_buf); ++ } ++ } ++ ++ return retval; ++} ++ ++static void mux_sched_send(void) ++{ ++ ++#ifdef USB_FOR_MUX ++ schedule_work(&send_tqueue); ++#else ++ if (!tq_serial_for_mux) { ++ TS0710_PRINTK("MUX Error: %s: tq_serial_for_mux == 0\n", ++ __FUNCTION__); ++ return; ++ } ++ schedule_work(&send_tqueue); ++ mark_bh(SERIAL_BH); ++#endif ++ ++} ++ ++/**************************** ++ * TTY driver routines ++*****************************/ ++ ++static void mux_close(struct tty_struct *tty, struct file *filp) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ int line; ++ __u8 dlci; ++ __u8 cmdtty; ++ __u8 datatty; ++ ++ UNUSED_PARAM(filp); ++ ++ if (!tty) { ++ return; ++ } ++ line = tty->index; ++ if ((line < 0) || (line >= NR_MUXS)) { ++ return; ++ } ++ if (mux_tty[line] > 0) ++ mux_tty[line]--; ++ ++ dlci = tty2dlci[line]; ++ cmdtty = dlci2tty[dlci].cmdtty; ++ datatty = dlci2tty[dlci].datatty; ++ if ((mux_tty[cmdtty] == 0) && (mux_tty[datatty] == 0)) { ++ if (dlci == 1) { ++ ts0710_close_channel(0); ++ TS0710_PRINTK ++ ("MUX mux_close: tapisrv might be down!!! Close DLCI 1\n"); ++ TS0710_SIG2APLOGD(); ++ } ++ ts0710_close_channel(dlci); ++ } ++ ++ if (mux_tty[line] == 0) { ++ if ((mux_send_info_flags[line]) ++ && (mux_send_info[line]) ++ /*&& (mux_send_info[line]->filled == 0) */ ++ ) { ++ mux_send_info_flags[line] = 0; ++ kfree(mux_send_info[line]); ++ mux_send_info[line] = 0; ++ TS0710_DEBUG("Free mux_send_info for /dev/mux%d", line); ++ } ++ ++ if ((mux_recv_info_flags[line]) ++ && (mux_recv_info[line]) ++ && (mux_recv_info[line]->total == 0)) { ++ mux_recv_info_flags[line] = 0; ++ free_mux_recv_struct(mux_recv_info[line]); ++ mux_recv_info[line] = 0; ++ TS0710_DEBUG("Free mux_recv_info for /dev/mux%d", line); ++ } ++ ++ ts0710_flow_on(dlci, ts0710); ++ schedule_work(&post_recv_tqueue); ++ ++ wake_up_interruptible(&tty->read_wait); ++ wake_up_interruptible(&tty->write_wait); ++ tty->packet = 0; ++ } ++} ++ ++static void mux_throttle(struct tty_struct *tty) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ int line; ++ int i; ++ __u8 dlci; ++ ++ if (!tty) { ++ return; ++ } ++ ++ line = tty->index; ++ if ((line < 0) || (line >= NR_MUXS)) { ++ return; ++ } ++ ++ TS0710_DEBUG("Enter into %s, minor number is: %d\n", __FUNCTION__, ++ line); ++ ++ dlci = tty2dlci[line]; ++ if ((ts0710->dlci[0].state != CONNECTED) ++ && (ts0710->dlci[0].state != FLOW_STOPPED)) { ++ return; ++ } else if ((ts0710->dlci[dlci].state != CONNECTED) ++ && (ts0710->dlci[dlci].state != FLOW_STOPPED)) { ++ return; ++ } ++ ++ if (ts0710->dlci[dlci].flow_control) { ++ return; ++ } ++ ++ for (i = 0; i < 3; i++) { ++ if (ts0710_msc_msg ++ (ts0710, EA | FC | RTC | RTR | DV, MCC_CMD, dlci) < 0) { ++ continue; ++ } else { ++ TS0710_LOG("MUX Send Flow off on dlci %d\n", dlci); ++ ts0710->dlci[dlci].flow_control = 1; ++ break; ++ } ++ } ++} ++ ++static void mux_unthrottle(struct tty_struct *tty) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ int line; ++ __u8 dlci; ++ mux_recv_struct *recv_info; ++ ++ if (!tty) { ++ return; ++ } ++ line = tty->index; ++ if ((line < 0) || (line >= NR_MUXS)) { ++ return; ++ } ++ ++ if ((!mux_recv_info_flags[line]) || (!mux_recv_info[line])) { ++ return; ++ } ++ ++ TS0710_DEBUG("Enter into %s, minor number is: %d\n", __FUNCTION__, ++ line); ++ ++ recv_info = mux_recv_info[line]; ++ dlci = tty2dlci[line]; ++ ++ if (recv_info->total) { ++ recv_info->post_unthrottle = 1; ++ schedule_work(&post_recv_tqueue); ++ } else { ++ ts0710_flow_on(dlci, ts0710); ++ } ++} ++ ++static int mux_chars_in_buffer(struct tty_struct *tty) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ int retval; ++ int line; ++ __u8 dlci; ++ mux_send_struct *send_info; ++ ++ retval = TS0710MUX_MAX_CHARS_IN_BUF; ++ if (!tty) { ++ goto out; ++ } ++ line = tty->index; ++ if ((line < 0) || (line >= NR_MUXS)) { ++ goto out; ++ } ++ ++ dlci = tty2dlci[line]; ++ if (ts0710->dlci[0].state == FLOW_STOPPED) { ++ TS0710_DEBUG ++ ("Flow stopped on all channels, returning MAX chars in buffer\n"); ++ goto out; ++ } else if (ts0710->dlci[dlci].state == FLOW_STOPPED) { ++ TS0710_DEBUG("Flow stopped, returning MAX chars in buffer\n"); ++ goto out; ++ } else if (ts0710->dlci[dlci].state != CONNECTED) { ++ TS0710_DEBUG("DLCI %d not connected\n", dlci); ++ goto out; ++ } ++ ++ if (!(mux_send_info_flags[line])) { ++ goto out; ++ } ++ send_info = mux_send_info[line]; ++ if (!send_info) { ++ goto out; ++ } ++ if (send_info->filled) { ++ goto out; ++ } ++ ++ retval = 0; ++ ++ out: ++ return retval; ++} ++ ++static int mux_chars_in_serial_buffer(struct tty_struct *tty) ++{ ++ UNUSED_PARAM(tty); ++ ++ if ((COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)) { ++ TS0710_PRINTK ++ ("MUX %s: (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)\n", ++ __FUNCTION__); ++ ++#ifndef USB_FOR_MUX ++ TS0710_PRINTK ++ ("MUX %s: tapisrv might be down!!! (serial_for_mux_driver == 0) || (serial_for_mux_tty == 0)\n", ++ __FUNCTION__); ++ TS0710_SIG2APLOGD(); ++#endif ++ ++ return 0; ++ } ++ return COMM_FOR_MUX_DRIVER->chars_in_buffer(COMM_FOR_MUX_TTY); ++} ++ ++static int mux_write(struct tty_struct *tty, ++ const unsigned char *buf, int count) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ int line; ++ __u8 dlci; ++ mux_send_struct *send_info; ++ __u8 *d_buf; ++ __u16 c; ++ __u8 post_recv; ++ ++ if (count <= 0) { ++ return 0; ++ } ++ ++ if (!tty) { ++ return 0; ++ } ++ ++ line = tty->index; ++ if ((line < 0) || (line >= NR_MUXS)) ++ return -ENODEV; ++ ++ dlci = tty2dlci[line]; ++ if (ts0710->dlci[0].state == FLOW_STOPPED) { ++ TS0710_DEBUG ++ ("Flow stopped on all channels, returning zero /dev/mux%d\n", ++ line); ++ return 0; ++ } else if (ts0710->dlci[dlci].state == FLOW_STOPPED) { ++ TS0710_DEBUG("Flow stopped, returning zero /dev/mux%d\n", line); ++ return 0; ++ } else if (ts0710->dlci[dlci].state == CONNECTED) { ++ ++ if (!(mux_send_info_flags[line])) { ++ TS0710_PRINTK ++ ("MUX Error: mux_write: mux_send_info_flags[%d] == 0\n", ++ line); ++ return -ENODEV; ++ } ++ send_info = mux_send_info[line]; ++ if (!send_info) { ++ TS0710_PRINTK ++ ("MUX Error: mux_write: mux_send_info[%d] == 0\n", ++ line); ++ return -ENODEV; ++ } ++ ++ c = min(count, (ts0710->dlci[dlci].mtu - 1)); ++ if (c <= 0) { ++ return 0; ++ } ++ ++ if (test_and_set_bit(BUF_BUSY, &send_info->flags)) ++ return 0; ++ ++ if (send_info->filled) { ++ clear_bit(BUF_BUSY, &send_info->flags); ++ return 0; ++ } ++ ++ d_buf = ((__u8 *) send_info->buf) + TS0710MUX_SEND_BUF_OFFSET; ++ memcpy(&d_buf[1], buf, c); ++ ++ TS0710_DEBUG("Prepare to send %d bytes from /dev/mux%d", c, ++ line); ++ if (iscmdtty[line]) { ++ TS0710_DEBUGSTR(&d_buf[1], c); ++ TS0710_DEBUG("CMDTAG"); ++ d_buf[0] = CMDTAG; ++ } else { ++ TS0710_DEBUG("DATATAG"); ++ d_buf[0] = DATATAG; ++ } ++ ++ TS0710_DEBUGHEX(d_buf, c + 1); ++ ++ send_info->frame = d_buf; ++ queue_uih(send_info, c + 1, ts0710, dlci); ++ send_info->filled = 1; ++ clear_bit(BUF_BUSY, &send_info->flags); ++ ++ post_recv = 0; ++ if (dlci == TS0710MUX_GPRS1_DLCI) { ++ if (add_count ++ (TS0710MUX_GPRS1_SEND_COUNT_IDX, c) < 0) { ++ post_recv_count_flag = 1; ++ post_recv = 1; ++ mux_data_count2[TS0710MUX_GPRS1_SEND_COUNT_IDX] ++ += c; ++ } ++ } else if (dlci == TS0710MUX_GPRS2_DLCI) { ++ if (add_count ++ (TS0710MUX_GPRS2_SEND_COUNT_IDX, c) < 0) { ++ post_recv_count_flag = 1; ++ post_recv = 1; ++ mux_data_count2[TS0710MUX_GPRS2_SEND_COUNT_IDX] ++ += c; ++ } ++ } ++ ++ if (post_recv) ++ schedule_work(&post_recv_tqueue); ++ ++ if (mux_chars_in_serial_buffer(COMM_FOR_MUX_TTY) == 0) { ++ /* Sending bottom half should be ++ run after return from this function */ ++ mux_sched_send(); ++ } ++ return c; ++ } else { ++ TS0710_PRINTK("MUX mux_write: DLCI %d not connected\n", dlci); ++ return -EDISCONNECTED; ++ } ++} ++ ++static int mux_write_room(struct tty_struct *tty) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ int retval; ++ int line; ++ __u8 dlci; ++ mux_send_struct *send_info; ++ ++ retval = 0; ++ if (!tty) { ++ goto out; ++ } ++ line = tty->index; ++ if ((line < 0) || (line >= NR_MUXS)) { ++ goto out; ++ } ++ ++ dlci = tty2dlci[line]; ++ if (ts0710->dlci[0].state == FLOW_STOPPED) { ++ TS0710_DEBUG("Flow stopped on all channels, returning ZERO\n"); ++ goto out; ++ } else if (ts0710->dlci[dlci].state == FLOW_STOPPED) { ++ TS0710_DEBUG("Flow stopped, returning ZERO\n"); ++ goto out; ++ } else if (ts0710->dlci[dlci].state != CONNECTED) { ++ TS0710_DEBUG("DLCI %d not connected\n", dlci); ++ goto out; ++ } ++ ++ if (!(mux_send_info_flags[line])) { ++ goto out; ++ } ++ send_info = mux_send_info[line]; ++ if (!send_info) { ++ goto out; ++ } ++ if (send_info->filled) { ++ goto out; ++ } ++ ++ retval = ts0710->dlci[dlci].mtu - 1; ++ ++ out: ++ return retval; ++} ++ ++static int mux_ioctl(struct tty_struct *tty, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ int line; ++ __u8 dlci; ++ ++ UNUSED_PARAM(file); ++ UNUSED_PARAM(arg); ++ ++ if (!tty) { ++ return -EIO; ++ } ++ line = tty->index; ++ if ((line < 0) || (line >= NR_MUXS)) { ++ return -ENODEV; ++ } ++ ++ dlci = tty2dlci[line]; ++ switch (cmd) { ++ case TS0710MUX_IO_MSC_HANGUP: ++ if (ts0710_msc_msg(ts0710, EA | RTR | DV, MCC_CMD, dlci) < 0) { ++ return -EAGAIN; ++ } else { ++ return 0; ++ } ++ ++ case TS0710MUX_IO_TEST_CMD: ++ return ts0710_exec_test_cmd(); ++/* ++ case TS0710MUX_IO_DLCI_FC_ON: ++ if( line == 0 ) { ++ break; ++ } ++ if( ts0710_msc_msg(ts0710, EA | RTC | RTR | DV, MCC_CMD, (__u8)line) < 0) { ++ return -EAGAIN; ++ } else { ++ return 0; ++ } ++ ++ case TS0710MUX_IO_DLCI_FC_OFF: ++ if( line == 0 ) { ++ break; ++ } ++ if( ts0710_msc_msg(ts0710, EA | FC | RTC | RTR | DV, MCC_CMD, (__u8)line) < 0) { ++ return -EAGAIN; ++ } else { ++ return 0; ++ } ++ ++ case TS0710MUX_IO_FC_ON: ++ if( line != 0 ) { ++ break; ++ } ++ if( ts0710_fcon_msg(ts0710, MCC_CMD) < 0) { ++ return -EAGAIN; ++ } else { ++ return 0; ++ } ++ ++ case TS0710MUX_IO_FC_OFF: ++ if( line != 0 ) { ++ break; ++ } ++ if( ts0710_fcoff_msg(ts0710, MCC_CMD) < 0) { ++ return -EAGAIN; ++ } else { ++ return 0; ++ } ++*/ ++ default: ++ break; ++ } ++ return -ENOIOCTLCMD; ++} ++ ++static void mux_flush_buffer(struct tty_struct *tty) ++{ ++ int line; ++ ++ if (!tty) { ++ return; ++ } ++ ++ line = tty->index; ++ if ((line < 0) || (line >= NR_MUXS)) { ++ return; ++ } ++ ++ TS0710_PRINTK("MUX %s: line is:%d\n", __FUNCTION__, line); ++ ++ if ((mux_send_info_flags[line]) ++ && (mux_send_info[line]) ++ && (mux_send_info[line]->filled)) { ++ ++ mux_send_info[line]->filled = 0; ++ } ++ ++ wake_up_interruptible(&tty->write_wait); ++#ifdef SERIAL_HAVE_POLL_WAIT ++ wake_up_interruptible(&tty->poll_wait); ++#endif ++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && ++ tty->ldisc.write_wakeup) { ++ (tty->ldisc.write_wakeup) (tty); ++ } ++ ++/* ++ if( (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0) ) { ++ TS0710_PRINTK("MUX %s: (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)\n", __FUNCTION__); ++ ++#ifndef USB_FOR_MUX ++ TS0710_PRINTK("MUX %s: tapisrv might be down!!! (serial_for_mux_driver == 0) || (serial_for_mux_tty == 0)\n", __FUNCTION__); ++ TS0710_SIG2APLOGD(); ++#endif ++ ++ return; ++ } ++ return COMM_FOR_MUX_DRIVER->flush_buffer(COMM_FOR_MUX_TTY); ++*/ ++} ++ ++static int mux_open(struct tty_struct *tty, struct file *filp) ++{ ++ int retval; ++ int line; ++ __u8 dlci; ++ __u8 cmdtty; ++ __u8 datatty; ++ mux_send_struct *send_info; ++ mux_recv_struct *recv_info; ++ ++ UNUSED_PARAM(filp); ++ ++ retval = -ENODEV; ++ if ((COMM_FOR_MUX_DRIVER == NULL) || (COMM_FOR_MUX_TTY == NULL)) { ++ ++#ifdef USB_FOR_MUX ++ TS0710_PRINTK("MUX: please install and open IPC-USB first\n"); ++#else ++ TS0710_PRINTK("MUX: please install and open ttyS0 first\n"); ++#endif ++ ++ goto out; ++ } ++ ++ if (!tty) { ++ goto out; ++ } ++ line = tty->index; ++ if ((line < 0) || (line >= NR_MUXS)) { ++ goto out; ++ } ++#ifdef TS0710SERVER ++ /* do nothing as a server */ ++ mux_tty[line]++; ++ retval = 0; ++#else ++ mux_tty[line]++; ++ dlci = tty2dlci[line]; ++ ++/* if( dlci == 1 ) { */ ++ /* Open server channel 0 first */ ++ if ((retval = ts0710_open_channel(0)) != 0) { ++ TS0710_PRINTK("MUX: Can't connect server channel 0!\n"); ++ ts0710_init(); ++ ++ mux_tty[line]--; ++ goto out; ++ } ++/* } */ ++ ++ /* Allocate memory first. As soon as connection has been established, MUX may receive */ ++ if (mux_send_info_flags[line] == 0) { ++ send_info = ++ (mux_send_struct *) kmalloc(sizeof(mux_send_struct), ++ GFP_KERNEL); ++ if (!send_info) { ++ retval = -ENOMEM; ++ ++ mux_tty[line]--; ++ goto out; ++ } ++ send_info->length = 0; ++ send_info->flags = 0; ++ send_info->filled = 0; ++ mux_send_info[line] = send_info; ++ mux_send_info_flags[line] = 1; ++ TS0710_DEBUG("Allocate mux_send_info for /dev/mux%d", line); ++ } ++ ++ if (mux_recv_info_flags[line] == 0) { ++ recv_info = ++ (mux_recv_struct *) kmalloc(sizeof(mux_recv_struct), ++ GFP_KERNEL); ++ if (!recv_info) { ++ mux_send_info_flags[line] = 0; ++ kfree(mux_send_info[line]); ++ mux_send_info[line] = 0; ++ TS0710_DEBUG("Free mux_send_info for /dev/mux%d", line); ++ retval = -ENOMEM; ++ ++ mux_tty[line]--; ++ goto out; ++ } ++ recv_info->length = 0; ++ recv_info->total = 0; ++ recv_info->mux_packet = 0; ++ recv_info->next = 0; ++ recv_info->no_tty = line; ++ recv_info->post_unthrottle = 0; ++ mux_recv_info[line] = recv_info; ++ mux_recv_info_flags[line] = 1; ++ TS0710_DEBUG("Allocate mux_recv_info for /dev/mux%d", line); ++ } ++ ++ /* Now establish DLCI connection */ ++ cmdtty = dlci2tty[dlci].cmdtty; ++ datatty = dlci2tty[dlci].datatty; ++ if ((mux_tty[cmdtty] > 0) || (mux_tty[datatty] > 0)) { ++ if ((retval = ts0710_open_channel(dlci)) != 0) { ++ TS0710_PRINTK("MUX: Can't connected channel %d!\n", ++ dlci); ++ ts0710_reset_dlci(dlci); ++ ++ mux_send_info_flags[line] = 0; ++ kfree(mux_send_info[line]); ++ mux_send_info[line] = 0; ++ TS0710_DEBUG("Free mux_send_info for /dev/mux%d", line); ++ ++ mux_recv_info_flags[line] = 0; ++ free_mux_recv_struct(mux_recv_info[line]); ++ mux_recv_info[line] = 0; ++ TS0710_DEBUG("Free mux_recv_info for /dev/mux%d", line); ++ ++ mux_tty[line]--; ++ goto out; ++ } ++ } ++ ++ retval = 0; ++#endif ++ out: ++ return retval; ++} ++ ++/* mux dispatcher, call from serial.c receiver_chars() */ ++void mux_dispatcher(struct tty_struct *tty) ++{ ++ UNUSED_PARAM(tty); ++ ++ schedule_work(&receive_tqueue); ++} ++ ++/*For BP UART problem Begin*/ ++#ifdef TS0710SEQ2 ++static int send_ack(ts0710_con * ts0710, __u8 seq_num, __u8 bp_seq1, ++ __u8 bp_seq2) ++#else ++static int send_ack(ts0710_con * ts0710, __u8 seq_num) ++#endif ++{ ++ __u8 buf[20]; ++ short_frame *ack; ++ ++#ifdef TS0710SEQ2 ++ static __u16 ack_seq = 0; ++#endif ++ ++ ack = (short_frame *) (buf + 1); ++ ack->h.addr.ea = 1; ++ ack->h.addr.cr = ((ts0710->initiator) & 0x1); ++ ack->h.addr.d = 0; ++ ack->h.addr.server_chn = 0; ++ ack->h.control = ACK; ++ ack->h.length.ea = 1; ++ ++#ifdef TS0710SEQ2 ++ ack->h.length.len = 5; ++ ack->data[0] = seq_num; ++ ack->data[1] = bp_seq1; ++ ack->data[2] = bp_seq2; ++ ack->data[3] = (ack_seq & 0xFF); ++ ack->data[4] = (ack_seq >> 8) & 0xFF; ++ ack_seq++; ++ ack->data[5] = crc_calc((__u8 *) ack, SHORT_CRC_CHECK); ++#else ++ ack->h.length.len = 1; ++ ack->data[0] = seq_num; ++ ack->data[1] = crc_calc((__u8 *) ack, SHORT_CRC_CHECK); ++#endif ++ ++ return basic_write(ts0710, buf, ++ (sizeof(short_frame) + FCS_SIZE + ++ ack->h.length.len)); ++} ++ ++/*For BP UART problem End*/ ++ ++static void receive_worker(void *private_) ++{ ++ struct tty_struct *tty = COMM_FOR_MUX_TTY; ++ int i, count; ++ static unsigned char tbuf[TS0710MUX_MAX_BUF_SIZE]; ++ static unsigned char *tbuf_ptr = &tbuf[0]; ++ static unsigned char *start_flag = 0; ++ unsigned char *search, *to, *from; ++ short_frame *short_pkt; ++ long_frame *long_pkt; ++ static int framelen = -1; ++ ++ /*For BP UART problem Begin */ ++ static __u8 expect_seq = 0; ++ __u32 crc_error; ++ __u8 *uih_data_start; ++ __u32 uih_len; ++ /*For BP UART problem End */ ++ ++ UNUSED_PARAM(private_); ++ ++ if (!tty) ++ return; ++ ++#ifdef USB_FOR_MUX ++ TS0710_DEBUG("Receive following bytes from IPC-USB"); ++#else ++ TS0710_DEBUG("Receive following bytes from UART"); ++#endif ++ ++ TS0710_DEBUGHEX(cp, count); ++ ++ if (count > (TS0710MUX_MAX_BUF_SIZE - (tbuf_ptr - tbuf))) { ++ TS0710_PRINTK ++ ("MUX receive_worker: !!!!! Exceed buffer boundary !!!!!\n"); ++ count = (TS0710MUX_MAX_BUF_SIZE - (tbuf_ptr - tbuf)); ++ } ++ ++ count = tty_buffer_request_room(tty, count); ++ ++ for (i = 0; i < count; i++) ++ tty_insert_flip_char(tty, tbuf_ptr[i], TTY_NORMAL); ++ ++ tbuf_ptr += count; ++ search = &tbuf[0]; ++ ++ if (test_and_set_bit(RECV_RUNNING, &mux_recv_flags)) { ++ schedule_work(&receive_tqueue); ++ return; ++ } ++ ++ if ((start_flag != 0) && (framelen != -1)) { ++ if ((tbuf_ptr - start_flag) < framelen) { ++ clear_bit(RECV_RUNNING, &mux_recv_flags); ++ return; ++ } ++ } ++ ++ while (1) { ++ if (start_flag == 0) { /* Frame Start Flag not found */ ++ framelen = -1; ++ while (search < tbuf_ptr) { ++ if (*search == TS0710_BASIC_FLAG) { ++ start_flag = search; ++ break; ++ } ++#ifdef TS0710LOG ++ else { ++ TS0710_LOG(">S %02x %c\n", *search, ++ *search); ++ } ++#endif ++ ++ search++; ++ } ++ ++ if (start_flag == 0) { ++ tbuf_ptr = &tbuf[0]; ++ break; ++ } ++ } else { /* Frame Start Flag found */ ++ /* 1 start flag + 1 address + 1 control + 1 or 2 length + lengths data + 1 FCS + 1 end flag */ ++ /* For BP UART problem 1 start flag + 1 seq_num + 1 address + ...... */ ++ /*if( (framelen == -1) && ((tbuf_ptr - start_flag) > TS0710_MAX_HDR_SIZE) ) */ ++ if ((framelen == -1) && ((tbuf_ptr - start_flag) > (TS0710_MAX_HDR_SIZE + SEQ_FIELD_SIZE))) { /*For BP UART problem */ ++ /*short_pkt = (short_frame *) (start_flag + 1); */ ++ short_pkt = (short_frame *) (start_flag + ADDRESS_FIELD_OFFSET); /*For BP UART problem */ ++ if (short_pkt->h.length.ea == 1) { /* short frame */ ++ /*framelen = TS0710_MAX_HDR_SIZE + short_pkt->h.length.len + 1; */ ++ framelen = TS0710_MAX_HDR_SIZE + short_pkt->h.length.len + 1 + SEQ_FIELD_SIZE; /*For BP UART problem */ ++ } else { /* long frame */ ++ /*long_pkt = (long_frame *) (start_flag + 1); */ ++ long_pkt = (long_frame *) (start_flag + ADDRESS_FIELD_OFFSET); /*For BP UART problem */ ++ /*framelen = TS0710_MAX_HDR_SIZE + GET_LONG_LENGTH( long_pkt->h.length ) + 2; */ ++ framelen = TS0710_MAX_HDR_SIZE + GET_LONG_LENGTH(long_pkt->h.length) + 2 + SEQ_FIELD_SIZE; /*For BP UART problem */ ++ } ++ ++ /*if( framelen > TS0710MUX_MAX_TOTAL_FRAME_SIZE ) { */ ++ if (framelen > (TS0710MUX_MAX_TOTAL_FRAME_SIZE + SEQ_FIELD_SIZE)) { /*For BP UART problem */ ++ TS0710_LOGSTR_FRAME(0, start_flag, ++ (tbuf_ptr - ++ start_flag)); ++ TS0710_PRINTK ++ ("MUX Error: %s: frame length:%d is bigger than Max total frame size:%d\n", ++ /*__FUNCTION__, framelen, TS0710MUX_MAX_TOTAL_FRAME_SIZE);*/ ++ __FUNCTION__, framelen, (TS0710MUX_MAX_TOTAL_FRAME_SIZE + SEQ_FIELD_SIZE)); /*For BP UART problem */ ++ search = start_flag + 1; ++ start_flag = 0; ++ framelen = -1; ++ continue; ++ } ++ } ++ ++ if ((framelen != -1) ++ && ((tbuf_ptr - start_flag) >= framelen)) { ++ if (*(start_flag + framelen - 1) == TS0710_BASIC_FLAG) { /* OK, We got one frame */ ++ ++ /*For BP UART problem Begin */ ++ TS0710_LOGSTR_FRAME(0, start_flag, ++ framelen); ++ TS0710_DEBUGHEX(start_flag, framelen); ++ ++ short_pkt = ++ (short_frame *) (start_flag + ++ ADDRESS_FIELD_OFFSET); ++ if ((short_pkt->h.length.ea) == 0) { ++ long_pkt = ++ (long_frame *) (start_flag + ++ ADDRESS_FIELD_OFFSET); ++ uih_len = ++ GET_LONG_LENGTH(long_pkt->h. ++ length); ++ uih_data_start = ++ long_pkt->h.data; ++ ++ crc_error = ++ crc_check((__u8 ++ *) (start_flag + ++ SLIDE_BP_SEQ_OFFSET), ++ LONG_CRC_CHECK + ++ 1, ++ *(uih_data_start + ++ uih_len)); ++ } else { ++ uih_len = ++ short_pkt->h.length.len; ++ uih_data_start = ++ short_pkt->data; ++ ++ crc_error = ++ crc_check((__u8 ++ *) (start_flag + ++ SLIDE_BP_SEQ_OFFSET), ++ SHORT_CRC_CHECK + ++ 1, ++ *(uih_data_start + ++ uih_len)); ++ } ++ ++ if (!crc_error) { ++ if (expect_seq == ++ *(start_flag + ++ SLIDE_BP_SEQ_OFFSET)) { ++ expect_seq++; ++ if (expect_seq >= 4) { ++ expect_seq = 0; ++ } ++#ifdef TS0710SEQ2 ++ send_ack ++ (&ts0710_connection, ++ expect_seq, ++ *(start_flag + ++ FIRST_BP_SEQ_OFFSET), ++ *(start_flag + ++ SECOND_BP_SEQ_OFFSET)); ++#else ++ send_ack ++ (&ts0710_connection, ++ expect_seq); ++#endif ++ ++ ts0710_recv_data ++ (&ts0710_connection, ++ start_flag + ++ ADDRESS_FIELD_OFFSET, ++ framelen - 2 - ++ SEQ_FIELD_SIZE); ++ } else { ++ ++#ifdef TS0710DEBUG ++ if (* ++ (start_flag + ++ SLIDE_BP_SEQ_OFFSET) ++ != 0x9F) { ++#endif ++ ++ TS0710_LOG ++ ("MUX sequence number %d is not expected %d, discard data!\n", ++ * ++ (start_flag ++ + ++ SLIDE_BP_SEQ_OFFSET), ++ expect_seq); ++ ++#ifdef TS0710SEQ2 ++ send_ack ++ (&ts0710_connection, ++ expect_seq, ++ * ++ (start_flag ++ + ++ FIRST_BP_SEQ_OFFSET), ++ * ++ (start_flag ++ + ++ SECOND_BP_SEQ_OFFSET)); ++#else ++ send_ack ++ (&ts0710_connection, ++ expect_seq); ++#endif ++ ++#ifdef TS0710DEBUG ++ } else { ++ *(uih_data_start ++ + uih_len) = ++ 0; ++ TS0710_PRINTK ++ ("MUX bp log: %s\n", ++ uih_data_start); ++ } ++#endif ++ ++ } ++ } else { /* crc_error */ ++ search = start_flag + 1; ++ start_flag = 0; ++ framelen = -1; ++ continue; ++ } /*End if(!crc_error) */ ++ ++ /*For BP UART problem End */ ++ ++/*For BP UART problem ++ TS0710_LOGSTR_FRAME(0, start_flag, framelen); ++ TS0710_DEBUGHEX(start_flag, framelen); ++ ts0710_recv_data(&ts0710_connection, start_flag + 1, framelen - 2); ++*/ ++ search = start_flag + framelen; ++ } else { ++ TS0710_LOGSTR_FRAME(0, start_flag, ++ framelen); ++ TS0710_DEBUGHEX(start_flag, framelen); ++ TS0710_PRINTK ++ ("MUX: Lost synchronization!\n"); ++ search = start_flag + 1; ++ } ++ ++ start_flag = 0; ++ framelen = -1; ++ continue; ++ } ++ ++ if (start_flag != &tbuf[0]) { ++ to = tbuf; ++ from = start_flag; ++ count = tbuf_ptr - start_flag; ++ while (count--) { ++ *to++ = *from++; ++ } ++ ++ tbuf_ptr -= (start_flag - tbuf); ++ start_flag = tbuf; ++ } ++ break; ++ } /* End Frame Start Flag found */ ++ } /* End while(1) */ ++ ++ clear_bit(RECV_RUNNING, &mux_recv_flags); ++} ++ ++static void post_recv_worker(void *private_) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ int tty_idx; ++ struct tty_struct *tty; ++ __u8 post_recv; ++ __u8 flow_control; ++ __u8 dlci; ++ mux_recv_struct *recv_info, *recv_info2, *post_recv_q; ++ int recv_room; ++ mux_recv_packet *recv_packet, *recv_packet2; ++ __u8 j; ++ ++ UNUSED_PARAM(private_); ++ ++ if (test_and_set_bit(RECV_RUNNING, &mux_recv_flags)) { ++ schedule_work(&post_recv_tqueue); ++ return; ++ } ++ ++ TS0710_DEBUG("Enter into post_recv_worker"); ++ ++ post_recv = 0; ++ if (!mux_recv_queue) { ++ goto out; ++ } ++ ++ post_recv_q = NULL; ++ recv_info2 = mux_recv_queue; ++ while ((recv_info = recv_info2)) { ++ recv_info2 = recv_info->next; ++ ++ if (!(recv_info->total)) { ++ TS0710_PRINTK ++ ("MUX Error: %s: Should not get here, recv_info->total == 0 \n", ++ __FUNCTION__); ++ continue; ++ } ++ ++ tty_idx = recv_info->no_tty; ++ dlci = tty2dlci[tty_idx]; ++ tty = mux_table[tty_idx]; ++ if ((!mux_tty[tty_idx]) || (!tty)) { ++ TS0710_PRINTK ++ ("MUX: No application waiting for, free recv_info! tty_idx:%d\n", ++ tty_idx); ++ mux_recv_info_flags[tty_idx] = 0; ++ free_mux_recv_struct(mux_recv_info[tty_idx]); ++ mux_recv_info[tty_idx] = 0; ++ ts0710_flow_on(dlci, ts0710); ++ continue; ++ } ++ ++ TS0710_DEBUG("/dev/mux%d recv_info->total is: %d", tty_idx, ++ recv_info->total); ++ ++ if (test_bit(TTY_THROTTLED, &tty->flags)) { ++ add_post_recv_queue(&post_recv_q, recv_info); ++ continue; ++ } else if (test_bit(TTY_DONT_FLIP, &tty->flags)) { ++ post_recv = 1; ++ add_post_recv_queue(&post_recv_q, recv_info); ++ continue; ++ } ++ ++ flow_control = 0; ++ recv_packet2 = recv_info->mux_packet; ++ while (recv_info->total) { ++ recv_room = 65535; ++ if (tty->receive_room) ++ recv_room = tty->receive_room; ++ ++ if (recv_info->length) { ++ if (recv_room < recv_info->length) { ++ flow_control = 1; ++ break; ++ } ++ ++ /* Put queued data into read buffer of tty */ ++ TS0710_DEBUG ++ ("Put queued recv data into read buffer of /dev/mux%d", ++ tty_idx); ++ TS0710_DEBUGHEX(recv_info->data, ++ recv_info->length); ++ (tty->ldisc.receive_buf) (tty, recv_info->data, ++ NULL, ++ recv_info->length); ++ recv_info->total -= recv_info->length; ++ recv_info->length = 0; ++ } else { /* recv_info->length == 0 */ ++ if ((recv_packet = recv_packet2)) { ++ recv_packet2 = recv_packet->next; ++ ++ if (recv_room < recv_packet->length) { ++ flow_control = 1; ++ recv_info->mux_packet = ++ recv_packet; ++ break; ++ } ++ ++ /* Put queued data into read buffer of tty */ ++ TS0710_DEBUG ++ ("Put queued recv data into read buffer of /dev/mux%d", ++ tty_idx); ++ TS0710_DEBUGHEX(recv_packet->data, ++ recv_packet->length); ++ (tty->ldisc.receive_buf) (tty, ++ recv_packet-> ++ data, NULL, ++ recv_packet-> ++ length); ++ recv_info->total -= recv_packet->length; ++ free_mux_recv_packet(recv_packet); ++ } else { ++ TS0710_PRINTK ++ ("MUX Error: %s: Should not get here, recv_info->total is:%u \n", ++ __FUNCTION__, recv_info->total); ++ } ++ } /* End recv_info->length == 0 */ ++ } /* End while( recv_info->total ) */ ++ ++ if (!(recv_info->total)) { ++ /* Important clear */ ++ recv_info->mux_packet = 0; ++ ++ if (recv_info->post_unthrottle) { ++ /* Do something for post_unthrottle */ ++ ts0710_flow_on(dlci, ts0710); ++ recv_info->post_unthrottle = 0; ++ } ++ } else { ++ add_post_recv_queue(&post_recv_q, recv_info); ++ ++ if (flow_control) { ++ /* Do something for flow control */ ++ if (recv_info->post_unthrottle) { ++ set_bit(TTY_THROTTLED, &tty->flags); ++ recv_info->post_unthrottle = 0; ++ } else { ++ ts0710_flow_off(tty, dlci, ts0710); ++ } ++ } /* End if( flow_control ) */ ++ } ++ } /* End while( (recv_info = recv_info2) ) */ ++ ++ mux_recv_queue = post_recv_q; ++ ++ out: ++ if (post_recv_count_flag) { ++ post_recv_count_flag = 0; ++ for (j = 0; j < TS0710MUX_COUNT_IDX_NUM; j++) { ++ if (mux_data_count2[j] > 0) { ++ if (add_count(j, mux_data_count2[j]) == 0) { ++ mux_data_count2[j] = 0; ++ } else { ++ post_recv_count_flag = 1; ++ post_recv = 1; ++ } ++ } ++ } /* End for (j = 0; j < TS0710MUX_COUNT_IDX_NUM; j++) */ ++ } ++ /* End if( post_recv_count_flag ) */ ++ if (post_recv) ++ schedule_work(&post_recv_tqueue); ++ clear_bit(RECV_RUNNING, &mux_recv_flags); ++} ++ ++/* mux sender, call from serial.c transmit_chars() */ ++void mux_sender(void) ++{ ++ mux_send_struct *send_info; ++ int chars; ++ __u8 idx; ++ ++ chars = mux_chars_in_serial_buffer(COMM_FOR_MUX_TTY); ++ if (!chars) { ++ /* chars == 0 */ ++ TS0710_LOG("<[]\n"); ++ mux_sched_send(); ++ return; ++ } ++ ++ idx = mux_send_info_idx; ++ if ((idx < NR_MUXS) && (mux_send_info_flags[idx])) { ++ send_info = mux_send_info[idx]; ++ if ((send_info) ++ && (send_info->filled) ++ && (send_info->length <= ++ (TS0710MUX_SERIAL_BUF_SIZE - chars))) { ++ ++ mux_sched_send(); ++ } ++ } ++} ++ ++static void send_worker(void *private_) ++{ ++ ts0710_con *ts0710 = &ts0710_connection; ++ __u8 j; ++ mux_send_struct *send_info; ++ int chars; ++ struct tty_struct *tty; ++ __u8 dlci; ++ ++ UNUSED_PARAM(private_); ++ ++ TS0710_DEBUG("Enter into send_worker"); ++ ++ mux_send_info_idx = NR_MUXS; ++ ++ if (ts0710->dlci[0].state == FLOW_STOPPED) { ++ TS0710_DEBUG("Flow stopped on all channels\n"); ++ return; ++ } ++ ++ for (j = 0; j < NR_MUXS; j++) { ++ ++ if (!(mux_send_info_flags[j])) { ++ continue; ++ } ++ ++ send_info = mux_send_info[j]; ++ if (!send_info) { ++ continue; ++ } ++ ++ if (!(send_info->filled)) { ++ continue; ++ } ++ ++ dlci = tty2dlci[j]; ++ if (ts0710->dlci[dlci].state == FLOW_STOPPED) { ++ TS0710_DEBUG("Flow stopped on channel DLCI: %d\n", ++ dlci); ++ continue; ++ } else if (ts0710->dlci[dlci].state != CONNECTED) { ++ TS0710_DEBUG("DLCI %d not connected\n", dlci); ++ send_info->filled = 0; ++ continue; ++ } ++ ++ chars = mux_chars_in_serial_buffer(COMM_FOR_MUX_TTY); ++ if (send_info->length <= (TS0710MUX_SERIAL_BUF_SIZE - chars)) { ++ TS0710_DEBUG("Send queued UIH for /dev/mux%d", j); ++ basic_write(ts0710, (__u8 *) send_info->frame, ++ send_info->length); ++ send_info->length = 0; ++ send_info->filled = 0; ++ } else { ++ mux_send_info_idx = j; ++ break; ++ } ++ } /* End for() loop */ ++ ++ /* Queue UIH data to be transmitted */ ++ for (j = 0; j < NR_MUXS; j++) { ++ ++ if (!(mux_send_info_flags[j])) { ++ continue; ++ } ++ ++ send_info = mux_send_info[j]; ++ if (!send_info) { ++ continue; ++ } ++ ++ if (send_info->filled) { ++ continue; ++ } ++ ++ /* Now queue UIH data to send_info->buf */ ++ ++ if (!mux_tty[j]) { ++ continue; ++ } ++ ++ tty = mux_table[j]; ++ if (!tty) { ++ continue; ++ } ++ ++ dlci = tty2dlci[j]; ++ if (ts0710->dlci[dlci].state == FLOW_STOPPED) { ++ TS0710_DEBUG("Flow stopped on channel DLCI: %d\n", ++ dlci); ++ continue; ++ } else if (ts0710->dlci[dlci].state != CONNECTED) { ++ TS0710_DEBUG("DLCI %d not connected\n", dlci); ++ continue; ++ } ++ ++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) ++ && tty->ldisc.write_wakeup) { ++ (tty->ldisc.write_wakeup) (tty); ++ } ++ wake_up_interruptible(&tty->write_wait); ++ ++#ifdef SERIAL_HAVE_POLL_WAIT ++ wake_up_interruptible(&tty->poll_wait); ++#endif ++ ++ if (send_info->filled) { ++ if (j < mux_send_info_idx) { ++ mux_send_info_idx = j; ++ } ++ } ++ } /* End for() loop */ ++} ++ ++static int get_count(__u8 idx) ++{ ++ int ret; ++ ++ if (idx > TS0710MUX_COUNT_MAX_IDX) { ++ TS0710_PRINTK("MUX get_count: invalid idx: %d!\n", idx); ++ return -1; ++ } ++ ++ down(&mux_data_count_mutex[idx]); ++ ret = mux_data_count[idx]; ++ up(&mux_data_count_mutex[idx]); ++ ++ return ret; ++} ++ ++static int set_count(__u8 idx, int count) ++{ ++ if (idx > TS0710MUX_COUNT_MAX_IDX) { ++ TS0710_PRINTK("MUX set_count: invalid idx: %d!\n", idx); ++ return -1; ++ } ++ if (count < 0) { ++ TS0710_PRINTK("MUX set_count: invalid count: %d!\n", count); ++ return -1; ++ } ++ ++ down(&mux_data_count_mutex[idx]); ++ mux_data_count[idx] = count; ++ up(&mux_data_count_mutex[idx]); ++ ++ return 0; ++} ++ ++static int add_count(__u8 idx, int count) ++{ ++ if (idx > TS0710MUX_COUNT_MAX_IDX) { ++ TS0710_PRINTK("MUX add_count: invalid idx: %d!\n", idx); ++ return -1; ++ } ++ if (count <= 0) { ++ TS0710_PRINTK("MUX add_count: invalid count: %d!\n", count); ++ return -1; ++ } ++ ++ if (down_trylock(&mux_data_count_mutex[idx])) ++ return -1; ++ mux_data_count[idx] += count; ++ up(&mux_data_count_mutex[idx]); ++ ++ return 0; ++} ++ ++ssize_t file_proc_read(struct file * file, char *buf, size_t size, ++ loff_t * ppos) ++{ ++ gprs_bytes gprsData[TS0710MUX_GPRS_SESSION_MAX]; ++ int bufLen = sizeof(gprs_bytes) * TS0710MUX_GPRS_SESSION_MAX; ++ ++ UNUSED_PARAM(file); ++ UNUSED_PARAM(size); ++ UNUSED_PARAM(ppos); ++ ++ gprsData[0].recvBytes = get_count(TS0710MUX_GPRS1_RECV_COUNT_IDX); ++ gprsData[0].sentBytes = get_count(TS0710MUX_GPRS1_SEND_COUNT_IDX); ++ gprsData[TS0710MUX_GPRS_SESSION_MAX - 1].recvBytes = ++ get_count(TS0710MUX_GPRS2_RECV_COUNT_IDX); ++ gprsData[TS0710MUX_GPRS_SESSION_MAX - 1].sentBytes = ++ get_count(TS0710MUX_GPRS2_SEND_COUNT_IDX); ++ ++ copy_to_user(buf, gprsData, bufLen); ++ ++ return bufLen; ++} ++ ++ssize_t file_proc_write(struct file * file, const char *buf, size_t count, ++ loff_t * ppos) ++{ ++ gprs_bytes gprsData[TS0710MUX_GPRS_SESSION_MAX]; ++ int bufLen = sizeof(gprs_bytes) * TS0710MUX_GPRS_SESSION_MAX; ++ ++ UNUSED_PARAM(file); ++ UNUSED_PARAM(count); ++ UNUSED_PARAM(ppos); ++ ++ memset(gprsData, 0, bufLen); ++ ++ copy_from_user(gprsData, buf, bufLen); ++ ++ set_count(TS0710MUX_GPRS1_RECV_COUNT_IDX, gprsData[0].recvBytes); ++ set_count(TS0710MUX_GPRS1_SEND_COUNT_IDX, gprsData[0].sentBytes); ++ set_count(TS0710MUX_GPRS2_RECV_COUNT_IDX, ++ gprsData[TS0710MUX_GPRS_SESSION_MAX - 1].recvBytes); ++ set_count(TS0710MUX_GPRS2_SEND_COUNT_IDX, ++ gprsData[TS0710MUX_GPRS_SESSION_MAX - 1].sentBytes); ++ ++ return bufLen; ++} ++ ++static void gprs_proc_init(void) ++{ ++ gprs_proc_file = ++ create_proc_entry("gprsbytes", S_IRUSR | S_IWUSR, NULL); ++ gprs_proc_file->proc_fops = &file_proc_operations; ++} ++ ++static void gprs_proc_exit(void) ++{ ++ remove_proc_entry("gprsbytes", gprs_proc_file); ++} ++ ++static int __init mux_init(void) ++{ ++ __u8 j; ++ ++ if (COMM_FOR_MUX_DRIVER == NULL) { ++ ++#ifdef USB_FOR_MUX ++ panic("please install IPC-USB first\n"); ++#else ++ panic("please install ttyS0 first\n"); ++#endif ++ ++ } ++ ++ ts0710_init(); ++ ++ for (j = 0; j < NR_MUXS; j++) { ++ mux_send_info_flags[j] = 0; ++ mux_send_info[j] = 0; ++ mux_recv_info_flags[j] = 0; ++ mux_recv_info[j] = 0; ++ } ++ mux_send_info_idx = NR_MUXS; ++ mux_recv_queue = NULL; ++ mux_recv_flags = 0; ++ ++ for (j = 0; j < TS0710MUX_COUNT_IDX_NUM; j++) { ++ mux_data_count[j] = 0; ++ mux_data_count2[j] = 0; ++ init_MUTEX(&mux_data_count_mutex[j]); ++ } ++ post_recv_count_flag = 0; ++ ++ INIT_WORK(&send_tqueue, send_worker, NULL); ++ INIT_WORK(&receive_tqueue, receive_worker, NULL); ++ INIT_WORK(&post_recv_tqueue, post_recv_worker, NULL); ++ ++ memset(&mux_driver, 0, sizeof(struct tty_driver)); ++ memset(&mux_tty, 0, sizeof(mux_tty)); ++ mux_driver.magic = TTY_DRIVER_MAGIC; ++ mux_driver.driver_name = "ts0710mux"; ++ mux_driver.name = "ts0710mux"; ++ mux_driver.major = TS0710MUX_MAJOR; ++ mux_driver.minor_start = TS0710MUX_MINOR_START; ++ mux_driver.num = NR_MUXS; ++ mux_driver.type = TTY_DRIVER_TYPE_SERIAL; ++ mux_driver.subtype = SERIAL_TYPE_NORMAL; ++ mux_driver.init_termios = tty_std_termios; ++ mux_driver.init_termios.c_iflag = 0; ++ mux_driver.init_termios.c_oflag = 0; ++ mux_driver.init_termios.c_cflag = B38400 | CS8 | CREAD; ++ mux_driver.init_termios.c_lflag = 0; ++ mux_driver.flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW; ++ ++ mux_driver.ttys = mux_table; ++ mux_driver.termios = mux_termios; ++ mux_driver.termios_locked = mux_termios_locked; ++// mux_driver.driver_state = mux_state; ++ mux_driver.other = NULL; ++ ++ mux_driver.open = mux_open; ++ mux_driver.close = mux_close; ++ mux_driver.write = mux_write; ++ mux_driver.write_room = mux_write_room; ++ mux_driver.flush_buffer = mux_flush_buffer; ++ mux_driver.chars_in_buffer = mux_chars_in_buffer; ++ mux_driver.throttle = mux_throttle; ++ mux_driver.unthrottle = mux_unthrottle; ++ mux_driver.ioctl = mux_ioctl; ++ mux_driver.owner = THIS_MODULE; ++ ++ if (tty_register_driver(&mux_driver)) ++ panic("Couldn't register mux driver"); ++ ++ COMM_MUX_DISPATCHER = mux_dispatcher; ++ COMM_MUX_SENDER = mux_sender; ++ ++ gprs_proc_init(); ++ ++ return 0; ++} ++ ++static void __exit mux_exit(void) ++{ ++ __u8 j; ++ ++ COMM_MUX_DISPATCHER = NULL; ++ COMM_MUX_SENDER = NULL; ++ ++ gprs_proc_exit(); ++ ++ mux_send_info_idx = NR_MUXS; ++ mux_recv_queue = NULL; ++ for (j = 0; j < NR_MUXS; j++) { ++ if ((mux_send_info_flags[j]) && (mux_send_info[j])) { ++ kfree(mux_send_info[j]); ++ } ++ mux_send_info_flags[j] = 0; ++ mux_send_info[j] = 0; ++ ++ if ((mux_recv_info_flags[j]) && (mux_recv_info[j])) { ++ free_mux_recv_struct(mux_recv_info[j]); ++ } ++ mux_recv_info_flags[j] = 0; ++ mux_recv_info[j] = 0; ++ } ++ ++ if (tty_unregister_driver(&mux_driver)) ++ panic("Couldn't unregister mux driver"); ++} ++ ++module_init(mux_init); ++module_exit(mux_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte <laforge@openezx.org>"); ++MODULE_DESCRIPTION("TS 07.10 Multiplexer"); +Index: linux-2.6.20.7/drivers/char/ts0710_mux.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/drivers/char/ts0710_mux.h 2007-04-21 18:04:56.000000000 +0200 +@@ -0,0 +1,103 @@ ++/* ++ * mux_macro.h ++ * ++ * Copyright (C) 2002 2005 Motorola ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * ++ * 11/18/2002 (Motorola) - Initial version ++ * ++ */ ++ ++/* ++* This header file should be included by both MUX and other applications ++* which access MUX device files. It gives the additional macro definitions ++* shared between MUX and applications. ++*/ ++ ++/* MUX DLCI(Data Link Connection Identifier) Configuration */ ++/* ++* DLCI Service ++* 0 Control Channel ++* 1 Voice Call & Network-related ++* 2 SMS MO ++* 3 SMS MT ++* 4 Phonebook & related ++* 5 MISC ++* 6 CSD/FAX ++* 7 GPRS1 ++* 8 GPRS2 ++* 9 Logger CMD ++* 10 Logger Data ++* 11 Test CMD ++* 12 AGPS ++* 13 Net Monitor ++*/ ++ ++/* Mapping between DLCI and MUX device files */ ++/* ++* File Name Minor DLCI AT Command/Data ++* /dev/mux0 0 1 AT Command ++* /dev/mux1 1 2 AT Command ++* /dev/mux2 2 3 AT Command ++* /dev/mux3 3 4 AT Command ++* /dev/mux4 4 5 AT Command ++* /dev/mux5 5 6 AT Command ++* /dev/mux6 6 7 AT Command ++* /dev/mux7 7 8 AT Command ++* /dev/mux8 8 6 Data ++* /dev/mux9 9 7 Data ++* /dev/mux10 10 8 Data ++* /dev/mux11 11 9 Data ++* /dev/mux12 12 10 Data ++* /dev/mux13 13 11 Data ++* /dev/mux14 14 12 Data ++* /dev/mux15 15 13 Data ++*/ ++ ++#define MUX_CMD_FILE_VOICE_CALL "/dev/mux0" ++#define MUX_CMD_FILE_SMS_MO "/dev/mux1" ++#define MUX_CMD_FILE_SMS_MT "/dev/mux2" ++#define MUX_CMD_FILE_PHONEBOOK "/dev/mux3" ++#define MUX_CMD_FILE_MISC "/dev/mux4" ++#define MUX_CMD_FILE_CSD "/dev/mux5" ++#define MUX_CMD_FILE_GPRS1 "/dev/mux6" ++#define MUX_CMD_FILE_GPRS2 "/dev/mux7" ++ ++#define MUX_DATA_FILE_CSD "/dev/mux8" ++#define MUX_DATA_FILE_GPRS1 "/dev/mux9" ++#define MUX_DATA_FILE_GPRS2 "/dev/mux10" ++#define MUX_DATA_FILE_LOGGER_CMD "/dev/mux11" ++#define MUX_DATA_FILE_LOGGER_DATA "/dev/mux12" ++#define MUX_DATA_FILE_TEST_CMD "/dev/mux13" ++#define MUX_DATA_FILE_AGPS "/dev/mux14" ++#define MUX_DATA_FILE_NET_MONITOR "/dev/mux15" ++ ++#define NUM_MUX_CMD_FILES 8 ++#define NUM_MUX_DATA_FILES 8 ++#define NUM_MUX_FILES ( NUM_MUX_CMD_FILES + NUM_MUX_DATA_FILES ) ++ ++/* Special ioctl() upon a MUX device file for hanging up a call */ ++#define TS0710MUX_IO_MSC_HANGUP 0x54F0 ++ ++/* Special ioctl() upon a MUX device file for MUX loopback test */ ++#define TS0710MUX_IO_TEST_CMD 0x54F1 ++ ++/* Special Error code might be return from write() to a MUX device file */ ++#define EDISCONNECTED 900 /* Logical data link is disconnected */ ++ ++/* Special Error code might be return from open() to a MUX device file */ ++#define EREJECTED 901 /* Logical data link connection request is rejected */ +Index: linux-2.6.20.7/drivers/char/ts0710_mux_usb.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/drivers/char/ts0710_mux_usb.c 2007-04-21 18:07:45.000000000 +0200 +@@ -0,0 +1,868 @@ ++/* ++ * linux/drivers/usb/ipcusb.c ++ * ++ * Implementation of a ipc driver based Intel's Bulverde USB Host ++ * Controller. ++ * ++ * Copyright (C) 2003-2005 Motorola ++ * Copyright (C) 2006 Harald Welte <laforge@openezx.org> ++ * ++ * 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 ++ * ++ * 2003-Nov-03 - (Motorola) created ++ * 2004-Feb-20 - (Motorola) Add Power Manager codes ++ * 2004-Apr-14 - (Motorola) Update Suspend/Resume codes ++ * 2004-May-10 - (Motorola) Add unlink_urbs codes and do some updates of send ++ * out urb sequence ++ * 2006-Jun-22 - (Harald Welte) port to Linux 2.6.x ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/list.h> ++#include <linux/errno.h> ++#include <asm/uaccess.h> ++#include <asm/hardware.h> ++#include <asm/arch/hardware.h> ++#include <asm/arch-pxa/pxa-regs.h> ++#include <asm/arch-pxa/ezx.h> ++#include <linux/slab.h> ++#include <linux/miscdevice.h> ++#include <linux/init.h> ++#include <linux/timer.h> ++#include <linux/delay.h> ++#include <linux/sched.h> ++#include <linux/tty.h> ++#include <linux/tty_driver.h> ++#include <linux/tty_flip.h> ++#include <linux/circ_buf.h> ++#include <linux/usb.h> ++ ++#include "ts0710_mux_usb.h" ++ ++/*Macro defined for this driver*/ ++#define DRIVER_VERSION "1.0alpha1" ++#define DRIVER_AUTHOR "Motorola / Harald Welte <laforge@openezx.org>" ++#define DRIVER_DESC "USB IPC Driver (TS07.10 lowlevel)" ++#define MOTO_IPC_VID 0x22b8 ++#define MOTO_IPC_PID 0x3006 ++#define IBUF_SIZE 32 /*urb size*/ ++#define IPC_USB_XMIT_SIZE 1024 ++#define IPC_URB_SIZE 32 ++#define IPC_USB_WRITE_INIT 0 ++#define IPC_USB_WRITE_XMIT 1 ++#define IPC_USB_PROBE_READY 3 ++#define IPC_USB_PROBE_NOT_READY 4 ++#define DBG_MAX_BUF_SIZE 1024 ++#define ICL_EVENT_INTERVAL (HZ) ++#undef BVD_DEBUG ++ ++#define IS_EP_BULK(ep) ((ep).bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0) ++#define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) ++#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) ++/*End defined macro*/ ++ ++/*global values defined*/ ++static struct usb_driver usb_ipc_driver; ++static struct timer_list ipcusb_timer; ++static struct timer_list suspend_timer; ++static struct timer_list wakeup_timer; ++static struct tty_struct ipcusb_tty; /* the coresponding tty struct, we just use flip buffer here. */ ++static struct tty_driver ipcusb_tty_driver; /* the coresponding tty driver, we just use write and chars in buff here*/ ++struct tty_driver *usb_for_mux_driver = NULL; ++struct tty_struct *usb_for_mux_tty = NULL; ++void (*usb_mux_dispatcher)(struct tty_struct *tty) = NULL; ++void (*usb_mux_sender)(void) = NULL; ++void (*ipcusb_ap_to_bp)(unsigned char*, int) = NULL; ++void (*ipcusb_bp_to_ap)(unsigned char*, int) = NULL; ++EXPORT_SYMBOL(usb_for_mux_driver); ++EXPORT_SYMBOL(usb_for_mux_tty); ++EXPORT_SYMBOL(usb_mux_dispatcher); ++EXPORT_SYMBOL(usb_mux_sender); ++EXPORT_SYMBOL(ipcusb_ap_to_bp); ++EXPORT_SYMBOL(ipcusb_bp_to_ap); ++static int sumbit_times = 0; ++static int callback_times = 0; ++//static unsigned long last_jiff = 0; ++extern int usbh_finished_resume; ++/*end global values defined*/ ++ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL"); ++ ++#ifdef BVD_DEBUG ++#define bvd_dbg(format, arg...) printk(__FILE__ ": " format "\n" , ## arg) ++#else ++#define bvd_dbg(format, arg...) do {} while (0) ++#endif ++ ++/* USB device context */ ++typedef struct { ++ struct list_head list; ++ int size; ++ char *body; ++} buf_list_t; ++ ++struct ipc_usb_data { ++ u_int8_t write_finished_flag; ++ u_int8_t write_flag, ++ ipc_flag, ++ suspend_flag; ++ struct usb_device *ipc_dev; ++ struct urb readurb_mux, ++ writeurb_mux, ++ writeurb_dsplog; ++ char *obuf, *ibuf; ++ int writesize; /* max packet size for the ++ output bulk endpoint * ++ transfer buffers */ ++ ++ struct circ_buf xmit; /* write cric bufffer */ ++ struct list_head in_buf_list; ++ char bulk_in_ep_mux, ++ bulk_out_ep_mux, ++ bulk_in_ep_dsplog; ++ unsigned int ifnum; ++ ++ struct tasklet_struct bh, ++ bh_bp; ++ ++ spinlock_t lock; ++}; ++ ++struct ipc_usb_data *bvd_ipc; ++ ++#ifdef BVD_DEBUG ++static void bvd_dbg_hex(__u8 *buf, int len) ++{ ++ static unsigned char tbuf[DBG_MAX_BUF_SIZE]; ++ int i, c; ++ ++ if (len <= 0) ++ return; ++ ++ c = 0; ++ for (i=0; (i < len) && (c < (DBG_MAX_BUF_SIZE - 3)); i++) { ++ sprintf(&tbuf[c], "%02x ",buf[i]); ++ c += 3; ++ } ++ tbuf[c] = 0; ++ ++ printk("%s: %s\n", __FUNCTION__, tbuf); ++} ++#else ++#define bvd_dbg_hex(buf, len) ++#endif ++ ++static int unlink_urbs(struct urb *urb) ++{ ++ unsigned long flags; ++ int retval; ++ ++ spin_lock_irqsave(&bvd_ipc->lock, flags); ++ ++ retval = usb_unlink_urb(urb); ++ if (retval != -EINPROGRESS && retval != 0) ++ printk("unlink urb err, %d", retval); ++ ++ spin_unlock_irqrestore(&bvd_ipc->lock, flags); ++ return retval; ++} ++ ++static void append_to_inbuf_list(struct urb *urb) ++{ ++ buf_list_t *inbuf; ++ int count = urb->actual_length; ++ ++ inbuf = kmalloc(sizeof(buf_list_t), GFP_KERNEL); ++ if (!inbuf) { ++ printk("append_to_inbuf_list: (%d) out of memory!\n", ++ sizeof(buf_list_t)); ++ return; ++ } ++ ++ inbuf->size = count; ++ inbuf->body = kmalloc(sizeof(char)*count, GFP_KERNEL); ++ if (!inbuf->body) { ++ kfree(inbuf); ++ printk("append_to_inbuf_list: (%d) out of memory!\n", ++ sizeof(char)*count); ++ return; ++ } ++ memcpy(inbuf->body, (unsigned char*)urb->transfer_buffer, count); ++ list_add_tail(&inbuf->list, &bvd_ipc->in_buf_list); ++} ++ ++static void ipcusb_timeout(unsigned long data) ++{ ++ struct tty_struct *tty = &ipcusb_tty; ++ struct urb *urb = (struct urb *)data; ++ ++ bvd_dbg("ipcusb_timeout***"); ++ ++ while (!(list_empty(&bvd_ipc->in_buf_list))) { ++ int count; ++ buf_list_t *inbuf; ++ struct list_head *ptr = NULL; ++ ++ ptr = bvd_ipc->in_buf_list.next; ++ inbuf = list_entry (ptr, buf_list_t, list); ++ count = inbuf->size; ++ if (tty_insert_flip_string(tty, inbuf->body, count) >= count) { ++ list_del(ptr); ++ kfree(inbuf->body); ++ inbuf->body = NULL; ++ kfree(inbuf); ++ } else { ++ bvd_dbg("ipcusb_timeout: bvd_ipc->in_buf_list empty!"); ++ break; ++ } ++ } ++ ++ if (usb_mux_dispatcher) ++ usb_mux_dispatcher(tty); /**call Liu changhui's func.**/ ++ ++ if (list_empty(&bvd_ipc->in_buf_list)) { ++ urb->actual_length = 0; ++ urb->dev = bvd_ipc->ipc_dev; ++ if (usb_submit_urb(urb, GFP_ATOMIC)) ++ bvd_dbg("ipcusb_timeout: failed resubmitting read urb"); ++ bvd_dbg("ipcusb_timeout: resubmited read urb"); ++ } else { ++ ipcusb_timer.data = (unsigned long)urb; ++ mod_timer(&ipcusb_timer, jiffies+(10*HZ/1000)); ++ } ++} ++ ++static void usb_ipc_read_bulk(struct urb *urb, struct pt_regs *regs) ++{ ++ buf_list_t *inbuf; ++ int count = urb->actual_length; ++ struct tty_struct *tty = &ipcusb_tty; ++ ++ bvd_dbg("usb_ipc_read_bulk: begining!"); ++ if (urb->status) ++ printk("nonzero read bulk status received: %d\n", urb->status); ++ ++ bvd_dbg("usb_ipc_read_bulk: urb->actual_length=%d", urb->actual_length); ++ bvd_dbg("usb_ipc_read_bulk: urb->transfer_buffer:"); ++ ++ bvd_dbg_hex((unsigned char*)urb->transfer_buffer, urb->actual_length); ++ ++ if (count > 0 && ((*ipcusb_bp_to_ap) != NULL)) ++ (*ipcusb_bp_to_ap)(urb->transfer_buffer, urb->actual_length); ++ ++ if (!(list_empty(&bvd_ipc->in_buf_list))) { ++ int need_mux = 0; ++ ++ bvd_dbg("usb_ipc_read_bulk: some urbs in_buf_list"); ++ if (count > 0) { ++ bvd_ipc->suspend_flag = 1; ++ append_to_inbuf_list(urb); /* append the current received urb */ ++#if 0 ++ if(jiffies - last_jiff > ICL_EVENT_INTERVAL) ++ { ++ last_jiff = jiffies; ++ queue_apm_event(KRNL_ICL, NULL); ++ } ++#endif ++ } ++ ++ while (!(list_empty(&bvd_ipc->in_buf_list))) { ++ struct list_head* ptr = NULL; ++ ptr = bvd_ipc->in_buf_list.next; ++ inbuf = list_entry(ptr, buf_list_t, list); ++ count = inbuf->size; ++ need_mux = 1; ++ ++ tty_insert_flip_string(tty, inbuf->body, count); ++ ++ list_del(ptr); ++ kfree(inbuf->body); ++ inbuf->body = NULL; ++ kfree(inbuf); ++ } ++ ++ if (usb_mux_dispatcher && need_mux) ++ usb_mux_dispatcher(tty); /* call Liu changhui's func. */ ++ ++ if (list_empty(&bvd_ipc->in_buf_list)) { ++ urb->actual_length = 0; ++ urb->dev = bvd_ipc->ipc_dev; ++ if (usb_submit_urb(urb, GFP_ATOMIC)) ++ bvd_dbg("usb_ipc_read_bulk: " ++ "failed resubmitting read urb"); ++ bvd_dbg("usb_ipc_read_bulk: resubmited read urb"); ++ } else { ++ ipcusb_timer.data = (unsigned long)urb; ++ mod_timer(&ipcusb_timer, jiffies+(10*HZ/1000)); ++ } ++ } else if (count > 0) { ++ bvd_dbg("usb_ipc_read_bulk: no urbs in_buf_list"); ++ bvd_ipc->suspend_flag = 1; ++ ++ if (tty_insert_flip_string(tty, urb->transfer_buffer, ++ count) < count) { ++ bvd_ipc->suspend_flag = 1; ++ append_to_inbuf_list(urb); ++ ipcusb_timer.data = (unsigned long)urb; ++ mod_timer(&ipcusb_timer, jiffies+(10*HZ/1000)); ++#if 0 ++ if(jiffies - last_jiff > ICL_EVENT_INTERVAL) ++ { ++ last_jiff = jiffies; ++ queue_apm_event(KRNL_ICL, NULL); ++ } ++#endif ++ } ++ ++ if (usb_mux_dispatcher) ++ usb_mux_dispatcher(tty); /* call Liu changhui's func. */ ++ ++ urb->actual_length = 0; ++ urb->dev = bvd_ipc->ipc_dev; ++ if (usb_submit_urb(urb, GFP_ATOMIC)) ++ bvd_dbg("failed resubmitting read urb"); ++#if 0 ++ if(jiffies - last_jiff > ICL_EVENT_INTERVAL) ++ { ++ last_jiff = jiffies; ++ queue_apm_event(KRNL_ICL, NULL); ++ } ++#endif ++ bvd_dbg("usb_ipc_read_bulk: resubmited read urb"); ++ } ++ ++ bvd_dbg("usb_ipc_read_bulk: completed!!!"); ++} ++ ++static void usb_ipc_write_bulk(struct urb *urb, struct pt_regs *regs) ++{ ++ callback_times++; ++ bvd_ipc->write_finished_flag = 1; ++ ++ bvd_dbg("usb_ipc_write_bulk: begining!"); ++ //printk("%s: write_finished_flag=%d\n", __FUNCTION__, bvd_ipc->write_finished_flag); ++ ++ if (urb->status) ++ printk("nonzero write bulk status received: %d\n", urb->status); ++ ++ if (usb_mux_sender) ++ usb_mux_sender(); /**call Liu changhui's func**/ ++ ++ //printk("usb_ipc_write_bulk: mark ipcusb_softint!\n"); ++ tasklet_schedule(&bvd_ipc->bh); ++ ++ bvd_dbg("usb_ipc_write_bulk: finished!"); ++} ++ ++static void wakeup_timeout(unsigned long data) ++{ ++ GPSR(GPIO_MCU_INT_SW) = GPIO_bit(GPIO_MCU_INT_SW); ++ bvd_dbg("wakup_timeout: send GPIO_MCU_INT_SW signal!"); ++} ++ ++static void suspend_timeout(unsigned long data) ++{ ++ if (bvd_ipc->suspend_flag == 1) { ++ bvd_ipc->suspend_flag = 0; ++ mod_timer(&suspend_timer, jiffies+(5000*HZ/1000)); ++ bvd_dbg("suspend_timeout: add the suspend timer again"); ++ } else { ++ unlink_urbs(&bvd_ipc->readurb_mux); ++ UHCRHPS3 = 0x4; ++ mdelay(40); ++ bvd_dbg("suspend_timeout: send SUSPEND signal! UHCRHPS3=0x%x", ++ UHCRHPS3); ++ } ++} ++ ++static void ipcusb_xmit_data(void) ++{ ++ int c, count = IPC_URB_SIZE; ++ int result = 0; ++ int buf_flag = 0; ++ int buf_num = 0; ++ ++ //printk("%s: sumbit_times=%d, callback_times=%d\n", __FUNCTION__, sumbit_times, callback_times); ++ if (bvd_ipc->write_finished_flag == 0) ++ return; ++ ++ while (1) { ++ c = CIRC_CNT_TO_END(bvd_ipc->xmit.head, bvd_ipc->xmit.tail, ++ IPC_USB_XMIT_SIZE); ++ if (count < c) ++ c = count; ++ if (c <= 0) ++ break; ++ ++ memcpy(bvd_ipc->obuf+buf_num, ++ bvd_ipc->xmit.buf + bvd_ipc->xmit.tail, c); ++ buf_flag = 1; ++ bvd_ipc->xmit.tail = ((bvd_ipc->xmit.tail + c) ++ & (IPC_USB_XMIT_SIZE-1)); ++ count -= c; ++ buf_num += c; ++ } ++ ++ if (buf_num == 0) { ++ bvd_dbg("ipcusb_xmit_data: buf_num=%d, add suspend_timer", ++ buf_num); ++ bvd_ipc->suspend_flag = 0; ++ mod_timer(&suspend_timer, jiffies+(5000*HZ/1000)); ++ } ++ ++ bvd_dbg("ipcusb_xmit_data: buf_num=%d", buf_num); ++ bvd_dbg("ipcusb_xmit_data: bvd_ipc->obuf: "); ++ ++ bvd_dbg_hex((bvd_ipc->obuf)-buf_num, buf_num); ++ ++ if (buf_flag) { ++ bvd_ipc->writeurb_mux.transfer_buffer_length = buf_num; ++ bvd_dbg("ipcusb_xmit_data: copy data to write urb finished! "); ++ ++ if ((UHCRHPS3 & 0x4) == 0x4) { ++ static int ret; ++ int time = 0; ++ ++ /* if BP sleep, wake up BP first */ ++ pxa_gpio_mode(GPIO_IN | 41); ++ if (GPIO_is_high(41)) { ++ if (GPIO_is_high(GPIO_MCU_INT_SW)) ++ GPCR(GPIO_MCU_INT_SW) = GPIO_bit(GPIO_MCU_INT_SW); ++ else ++ GPSR(GPIO_MCU_INT_SW) = GPIO_bit(GPIO_MCU_INT_SW); ++ ++ time = jiffies; ++ while (GPIO_is_high(41) && (jiffies < (time+HZ))); ++ ++ if (GPIO_is_high(41)) { ++ printk("%s: Wakeup BP timeout! BP state is %d\n", ++ __FUNCTION__, GPIO_is_high(41)); ++ } ++ if (GPIO_is_high(GPIO_MCU_INT_SW)) ++ GPCR(GPIO_MCU_INT_SW) = GPIO_bit(GPIO_MCU_INT_SW); ++ else ++ GPSR(GPIO_MCU_INT_SW) = GPIO_bit(GPIO_MCU_INT_SW); ++ } ++ ++ /* Resume BP */ ++ UHCRHPS3 = 0x8; ++ mdelay(40); ++ bvd_dbg("ipcusb_xmit_data: Send RESUME signal! UHCRHPS3=0x%x", ++ UHCRHPS3); ++ /*send IN token*/ ++ bvd_ipc->readurb_mux.actual_length = 0; ++ bvd_ipc->readurb_mux.dev = bvd_ipc->ipc_dev; ++ if (ret = usb_submit_urb(&bvd_ipc->readurb_mux, GFP_ATOMIC)) ++ printk("ipcusb_xmit_data: usb_submit_urb(read mux bulk)" ++ "failed! status=%d\n", ret); ++ bvd_dbg("ipcusb_xmit_data: Send a IN token successfully!"); ++ } ++ ++ sumbit_times++; ++ bvd_ipc->write_finished_flag = 0; ++ //printk("%s: clear write_finished_flag:%d\n", __FUNCTION__, bvd_ipc->write_finished_flag); ++ bvd_ipc->writeurb_mux.dev = bvd_ipc->ipc_dev; ++ if (result = usb_submit_urb(&bvd_ipc->writeurb_mux, GFP_ATOMIC)) ++ warn("ipcusb_xmit_data: funky result! result=%d\n", result); ++ ++ bvd_dbg("ipcusb_xmit_data: usb_submit_urb finished! result:%d", result); ++ ++ } ++} ++ ++static void usbipc_bh_func(unsigned long param) ++{ ++ ipcusb_xmit_data(); ++} ++ ++extern void get_halted_bit(void); ++ ++static void usbipc_bh_bp_func(unsigned long param) ++{ ++ if ((UHCRHPS3 & 0x4) == 0x4) { ++ UHCRHPS3 = 0x8; ++ mdelay(40); ++ bvd_dbg("ipcusb_softint_send_readurb: Send RESUME signal! " ++ "UHCRHPS3=0x%x", UHCRHPS3); ++ } ++ if (bvd_ipc->ipc_flag == IPC_USB_PROBE_READY) { ++ get_halted_bit(); ++ ++ /*send a IN token*/ ++ bvd_ipc->readurb_mux.dev = bvd_ipc->ipc_dev; ++ if (usb_submit_urb(&bvd_ipc->readurb_mux, GFP_ATOMIC)) { ++ bvd_dbg("ipcusb_softint_send_readurb: " ++ "usb_submit_urb(read mux bulk) failed!"); ++ } ++ bvd_dbg("ipcusb_softint_send_readurb: Send a IN token successfully!"); ++ bvd_ipc->suspend_flag = 0; ++ bvd_dbg("ipcusb_softint_send_readurb: add suspend_timer"); ++ mod_timer(&suspend_timer, jiffies+(5000*HZ/1000)); ++ } ++} ++ ++static int usb_ipc_write(struct tty_struct *tty, ++ const unsigned char *buf, int count) ++{ ++ int c, ret = 0; ++ ++ bvd_dbg("usb_ipc_write: count=%d, buf: ", count); ++ bvd_dbg_hex(buf, count); ++ ++ if (count <= 0) ++ return 0; ++ ++ if (*ipcusb_ap_to_bp != NULL) ++ (*ipcusb_ap_to_bp)(buf, count); ++ ++ bvd_ipc->suspend_flag = 1; ++ ++ if ((bvd_ipc->ipc_flag == IPC_USB_PROBE_READY) && ++ (bvd_ipc->xmit.head == bvd_ipc->xmit.tail)) { ++ bvd_dbg("usb_ipc_write: set write_flag"); ++ bvd_ipc->write_flag = IPC_USB_WRITE_XMIT; ++ } ++ ++ while (1) { ++ c = CIRC_SPACE_TO_END(bvd_ipc->xmit.head, ++ bvd_ipc->xmit.tail, IPC_USB_XMIT_SIZE); ++ if (count < c) ++ c = count; ++ if (c <= 0) ++ break; ++ ++ memcpy(bvd_ipc->xmit.buf + bvd_ipc->xmit.head, buf, c); ++ bvd_ipc->xmit.head = ((bvd_ipc->xmit.head + c) ++ & (IPC_USB_XMIT_SIZE-1)); ++ buf += c; ++ count -= c; ++ ret += c; ++ } ++ bvd_dbg("usb_ipc_write: ret=%d, bvd_ipc->xmit.buf: ", ret); ++ ++ bvd_dbg_hex(bvd_ipc->xmit.buf, ret); ++ ++ if (bvd_ipc->write_flag == IPC_USB_WRITE_XMIT) { ++ bvd_ipc->write_flag = IPC_USB_WRITE_INIT; ++ bvd_dbg("usb_ipc_write: mark ipcusb_softint"); ++ tasklet_schedule(&bvd_ipc->bh); ++ } ++ ++ bvd_dbg("usb_ipc_write: ret=%d\n", ret); ++ return ret; ++} ++ ++static int usb_ipc_chars_in_buffer(struct tty_struct *tty) ++{ ++ return CIRC_CNT(bvd_ipc->xmit.head, bvd_ipc->xmit.tail, IPC_USB_XMIT_SIZE); ++} ++ ++void usb_send_readurb(void) ++{ ++ //printk("usb_send_readurb: begining!UHCRHPS3=0x%x, usbh_finished_resume=%d\n", UHCRHPS3, usbh_finished_resume); ++ ++ if (usbh_finished_resume == 0) ++ return; ++ ++ tasklet_schedule(&bvd_ipc->bh_bp); ++} ++ ++static int usb_ipc_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ struct usb_device *usbdev = interface_to_usbdev(intf); ++ struct usb_config_descriptor *ipccfg; ++ struct usb_interface_descriptor *interface; ++ struct usb_endpoint_descriptor *endpoint; ++ int ep_cnt, readsize, writesize; ++ char have_bulk_in_mux, have_bulk_out_mux; ++ ++ bvd_dbg("usb_ipc_probe: vendor id 0x%x, device id 0x%x", ++ usbdev->descriptor.idVendor, usbdev->descriptor.idProduct); ++ ++ if ((usbdev->descriptor.idVendor != MOTO_IPC_VID) || ++ (usbdev->descriptor.idProduct != MOTO_IPC_PID)) ++ return -ENODEV; ++ ++ /* a2590c : dsplog interface is not supported by this driver */ ++ if (intf->minor == 2) /* dsplog interface number is 2 */ ++ return -1; ++ ++ bvd_dbg("usb_ipc_probe: USB dev address:%p", usbdev); ++ bvd_dbg("usb_ipc_probe: ifnum:%u", intf->minor); ++ ++ ipccfg = &usbdev->actconfig->desc; ++ bvd_dbg("usb_ipc_prob: config%d", ipccfg->bConfigurationValue); ++ bvd_dbg("usb_ipc_prob: bNumInterfaces = %d", ipccfg->bNumInterfaces); ++ ++ /* After this point we can be a little noisy about what we are trying ++ * to configure, hehe. */ ++ if (usbdev->descriptor.bNumConfigurations != 1) { ++ info("usb_ipc_probe: Only one device configuration " ++ "is supported."); ++ return -1; ++ } ++ ++ if (usbdev->config[0].desc.bNumInterfaces != 3) { ++ info("usb_ipc_probe: Only three device interfaces are " ++ "supported."); ++ return -1; ++ } ++ ++ interface = &intf->cur_altsetting->desc; ++ endpoint = &intf->cur_altsetting->endpoint[0].desc; ++ /* Start checking for two bulk endpoints or ... FIXME: This is a future ++ * enhancement...*/ ++ bvd_dbg("usb_ipc_probe: Number of Endpoints:%d", ++ (int) interface->bNumEndpoints); ++ if (interface->bNumEndpoints != 2) { ++ info("usb_ipc_probe: Only two endpoints supported."); ++ return -1; ++ } ++ ++ ep_cnt = have_bulk_in_mux = have_bulk_out_mux = 0; ++ ++ bvd_dbg("usb_ipc_probe: endpoint[0] is:%x", ++ (&endpoint[0])->bEndpointAddress); ++ bvd_dbg("usb_ipc_probe: endpoint[1] is:%x ", ++ (&endpoint[1])->bEndpointAddress); ++ ++ while (ep_cnt < interface->bNumEndpoints) { ++ ++ if (!have_bulk_in_mux && IS_EP_BULK_IN(endpoint[ep_cnt])) { ++ bvd_dbg("usb_ipc_probe: bEndpointAddress(IN) is:%x ", ++ (&endpoint[ep_cnt])->bEndpointAddress); ++ have_bulk_in_mux = ++ (&endpoint[ep_cnt])->bEndpointAddress; ++ readsize = (&endpoint[ep_cnt])->wMaxPacketSize; ++ bvd_dbg("usb_ipc_probe: readsize=%d", readsize); ++ ep_cnt++; ++ continue; ++ } ++ ++ if (!have_bulk_out_mux && IS_EP_BULK_OUT(endpoint[ep_cnt])) { ++ bvd_dbg("usb_ipc_probe: bEndpointAddress(OUT) is:%x ", ++ (&endpoint[ep_cnt])->bEndpointAddress); ++ have_bulk_out_mux = ++ (&endpoint[ep_cnt])->bEndpointAddress; ++ writesize = (&endpoint[ep_cnt])->wMaxPacketSize; ++ bvd_dbg("usb_ipc_probe: writesize=%d", writesize); ++ ep_cnt++; ++ continue; ++ } ++ ++ info("usb_ipc_probe: Undetected endpoint ^_^ "); ++ /* Shouldn't ever get here unless we have something weird */ ++ return -1; ++ } ++ ++ /* Perform a quick check to make sure that everything worked as it ++ * should have. */ ++ ++ switch (interface->bNumEndpoints) { ++ case 2: ++ if (!have_bulk_in_mux || !have_bulk_out_mux) { ++ info("usb_ipc_probe: Two bulk endpoints required."); ++ return -1; ++ } ++ break; ++ default: ++ info("usb_ipc_probe: Endpoint determination failed ^_^ "); ++ return -1; ++ } ++ ++ /* Ok, now initialize all the relevant values */ ++ if (!(bvd_ipc->obuf = (char *)kmalloc(writesize, GFP_KERNEL))) { ++ err("usb_ipc_probe: Not enough memory for the output buffer."); ++ kfree(bvd_ipc); ++ return -1; ++ } ++ bvd_dbg("usb_ipc_probe: obuf address:%p", bvd_ipc->obuf); ++ ++ if (!(bvd_ipc->ibuf = (char *)kmalloc(readsize, GFP_KERNEL))) { ++ err("usb_ipc_probe: Not enough memory for the input buffer."); ++ kfree(bvd_ipc->obuf); ++ kfree(bvd_ipc); ++ return -1; ++ } ++ bvd_dbg("usb_ipc_probe: ibuf address:%p", bvd_ipc->ibuf); ++ ++ bvd_ipc->ipc_flag = IPC_USB_PROBE_READY; ++ bvd_ipc->write_finished_flag = 1; ++ bvd_ipc->suspend_flag = 1; ++ bvd_ipc->bulk_in_ep_mux= have_bulk_in_mux; ++ bvd_ipc->bulk_out_ep_mux= have_bulk_out_mux; ++ bvd_ipc->ipc_dev = usbdev; ++ bvd_ipc->writesize = writesize; ++ INIT_LIST_HEAD (&bvd_ipc->in_buf_list); ++ ++ bvd_ipc->bh.func = usbipc_bh_func; ++ bvd_ipc->bh.data = (unsigned long) bvd_ipc; ++ ++ bvd_ipc->bh_bp.func = usbipc_bh_bp_func; ++ bvd_ipc->bh_bp.data = (unsigned long) bvd_ipc; ++ ++ /*Build a write urb*/ ++ usb_fill_bulk_urb(&bvd_ipc->writeurb_mux, usbdev, ++ usb_sndbulkpipe(bvd_ipc->ipc_dev, ++ bvd_ipc->bulk_out_ep_mux), ++ bvd_ipc->obuf, writesize, usb_ipc_write_bulk, ++ bvd_ipc); ++ //bvd_ipc->writeurb_mux.transfer_flags |= USB_ASYNC_UNLINK; ++ ++ /*Build a read urb and send a IN token first time*/ ++ usb_fill_bulk_urb(&bvd_ipc->readurb_mux, usbdev, ++ usb_rcvbulkpipe(usbdev, bvd_ipc->bulk_in_ep_mux), ++ bvd_ipc->ibuf, readsize, usb_ipc_read_bulk, bvd_ipc); ++ //bvd_ipc->readurb_mux.transfer_flags |= USB_ASYNC_UNLINK; ++ ++ usb_driver_claim_interface(&usb_ipc_driver, intf, bvd_ipc); ++ //usb_driver_claim_interface(&usb_ipc_driver, &ipccfg->interface[1], bvd_ipc); ++ ++ // a2590c: dsplog is not supported by this driver ++ // usb_driver_claim_interface(&usb_ipc_driver, ++ // &ipccfg->interface[2], bvd_ipc); ++ /*send a IN token first time*/ ++ bvd_ipc->readurb_mux.dev = bvd_ipc->ipc_dev; ++ if (usb_submit_urb(&bvd_ipc->readurb_mux, GFP_ATOMIC)) ++ printk("usb_ipc_prob: usb_submit_urb(read mux bulk) failed!\n"); ++ ++ bvd_dbg("usb_ipc_prob: Send a IN token successfully!"); ++ ++ if (bvd_ipc->xmit.head != bvd_ipc->xmit.tail) { ++ printk("usb_ipc_probe: mark ipcusb_softint!\n"); ++ tasklet_schedule(&bvd_ipc->bh); ++ } ++ ++ printk("usb_ipc_probe: completed probe!"); ++ usb_set_intfdata(intf, &bvd_ipc); ++ return 0; ++} ++ ++static void usb_ipc_disconnect(struct usb_interface *intf) ++{ ++ //struct usb_device *usbdev = interface_to_usbdev(intf); ++ struct ipc_usb_data *bvd_ipc_disconnect = usb_get_intfdata(intf); ++ ++ printk("usb_ipc_disconnect:*** \n"); ++ ++ if ((UHCRHPS3 & 0x4) == 0) ++ usb_unlink_urb(&bvd_ipc_disconnect->readurb_mux); ++ ++ usb_unlink_urb(&bvd_ipc_disconnect->writeurb_mux); ++ ++ bvd_ipc_disconnect->ipc_flag = IPC_USB_PROBE_NOT_READY; ++ kfree(bvd_ipc_disconnect->ibuf); ++ kfree(bvd_ipc_disconnect->obuf); ++ ++ usb_driver_release_interface(&usb_ipc_driver, ++ bvd_ipc_disconnect->ipc_dev->actconfig->interface[0]); ++ usb_driver_release_interface(&usb_ipc_driver, ++ bvd_ipc_disconnect->ipc_dev->actconfig->interface[1]); ++ ++ //a2590c: dsplog interface is not supported by this driver ++ //usb_driver_release_interface(&usb_ipc_driver, &bvd_ipc_disconnect->ipc_dev->actconfig->interface[2]); ++ ++ bvd_ipc_disconnect->ipc_dev = NULL; ++ ++ usb_set_intfdata(intf, NULL); ++ ++ printk("usb_ipc_disconnect completed!\n"); ++} ++ ++static struct usb_device_id usb_ipc_id_table[] = { ++ { USB_DEVICE(MOTO_IPC_VID, MOTO_IPC_PID) }, ++ { } /* Terminating entry */ ++}; ++ ++static struct usb_driver usb_ipc_driver = { ++ .name = "usb ipc", ++ .probe = usb_ipc_probe, ++ .disconnect = usb_ipc_disconnect, ++ .id_table = usb_ipc_id_table, ++}; ++ ++static int __init usb_ipc_init(void) ++{ ++ int result; ++ ++ bvd_dbg("init usb_ipc"); ++ /* register driver at the USB subsystem */ ++ result = usb_register(&usb_ipc_driver); ++ if (result < 0) { ++ err ("usb ipc driver could not be registered"); ++ return result; ++ } ++ ++ /*init the related mux interface*/ ++ if (!(bvd_ipc = kzalloc(sizeof(struct ipc_usb_data), GFP_KERNEL))) { ++ err("usb_ipc_init: Out of memory."); ++ usb_deregister(&usb_ipc_driver); ++ return -ENOMEM; ++ } ++ bvd_dbg("usb_ipc_init: Address of bvd_ipc:%p", bvd_ipc); ++ ++ if (!(bvd_ipc->xmit.buf = kmalloc(IPC_USB_XMIT_SIZE, GFP_KERNEL))) { ++ err("usb_ipc_init: Not enough memory for the input buffer."); ++ kfree(bvd_ipc); ++ usb_deregister(&usb_ipc_driver); ++ return -ENOMEM; ++ } ++ bvd_dbg("usb_ipc_init: bvd_ipc->xmit.buf address:%p", ++ bvd_ipc->xmit.buf); ++ bvd_ipc->ipc_dev = NULL; ++ bvd_ipc->xmit.head = bvd_ipc->xmit.tail = 0; ++ bvd_ipc->write_flag = IPC_USB_WRITE_INIT; ++ ++ ipcusb_tty_driver.write = usb_ipc_write; ++ ipcusb_tty_driver.chars_in_buffer = usb_ipc_chars_in_buffer; ++ ++ usb_for_mux_driver = &ipcusb_tty_driver; ++ usb_for_mux_tty = &ipcusb_tty; ++ ++ /* init timers for ipcusb read process and usb suspend */ ++ init_timer(&ipcusb_timer); ++ ipcusb_timer.function = ipcusb_timeout; ++ ++ init_timer(&suspend_timer); ++ suspend_timer.function = suspend_timeout; ++ ++ init_timer(&wakeup_timer); ++ wakeup_timer.function = wakeup_timeout; ++ ++ info("USB Host(Bulverde) IPC driver registered."); ++ info(DRIVER_VERSION ":" DRIVER_DESC); ++ ++ return 0; ++} ++ ++static void __exit usb_ipc_exit(void) ++{ ++ bvd_dbg("cleanup bvd_ipc"); ++ ++ kfree(bvd_ipc->xmit.buf); ++ kfree(bvd_ipc); ++ usb_deregister(&usb_ipc_driver); ++ ++ info("USB Host(Bulverde) IPC driver deregistered."); ++} ++ ++module_init(usb_ipc_init); ++module_exit(usb_ipc_exit); ++EXPORT_SYMBOL(usb_send_readurb); +Index: linux-2.6.20.7/drivers/char/ts0710_mux_usb.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/drivers/char/ts0710_mux_usb.h 2007-04-21 18:07:21.000000000 +0200 +@@ -0,0 +1,29 @@ ++/* ++ * linux/drivers/usb/ipcusb.h ++ * ++ * Implementation of a ipc driver based Intel's Bulverde USB Host ++ * Controller. ++ * ++ * Copyright (C) 2003-2005 Motorola ++ * ++ * 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 ++ * ++ * 2003-Nov-18 - (Motorola) created ++ * ++ */ ++extern struct tty_driver *usb_for_mux_driver; ++extern struct tty_struct *usb_for_mux_tty; ++extern void (*usb_mux_dispatcher)(struct tty_struct *tty); ++extern void (*usb_mux_sender)(void); diff --git a/packages/linux/linux-ezx-2.6.20.7/mux_debug.patch b/packages/linux/linux-ezx-2.6.20.7/mux_debug.patch new file mode 100644 index 0000000000..58cb25a0b6 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/mux_debug.patch @@ -0,0 +1,551 @@ +Index: linux-2.6.20.7/drivers/char/ts0710_mux.c +=================================================================== +--- linux-2.6.20.7.orig/drivers/char/ts0710_mux.c 2007-04-22 12:24:18.000000000 +0200 ++++ linux-2.6.20.7/drivers/char/ts0710_mux.c 2007-04-22 12:26:47.000000000 +0200 +@@ -85,6 +85,9 @@ + #include "ts0710.h" + #include "ts0710_mux.h" + ++#define TS0710DEBUG ++#define PRINT_OUTPUT_PRINTK ++ + #define TS0710MUX_GPRS_SESSION_MAX 2 + #define TS0710MUX_MAJOR 250 + #define TS0710MUX_MINOR_START 0 +@@ -316,7 +319,7 @@ + #ifdef TS0710DEBUG + + #ifdef PRINT_OUTPUT_PRINTK +-#define TS0710_DEBUG(fmt, arg...) printk(KERN_INFO "MUX " __FUNCTION__ ": " fmt "\n" , ## arg) ++#define TS0710_DEBUG(fmt, arg...) printk(KERN_INFO "MUX %s: " fmt "\n" , __func__, ## arg) + #else + #include "ezxlog.h" + static __u8 strDebug[256]; +@@ -530,10 +533,10 @@ + if (strncmp(p->comm, "aplogd", 6) == 0) { + sig = 1; + if (send_sig(SIGUSR2, p, 1) == 0) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX: success to send SIGUSR2 to aplogd!\n"); + } else { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX: failure to send SIGUSR2 to aplogd!\n"); + } + break; +@@ -542,7 +545,7 @@ + read_unlock(&tasklist_lock); + + if (!sig) { +- TS0710_PRINTK("MUX: not found aplogd!\n"); ++ TS0710_DEBUG("MUX: not found aplogd!\n"); + } + } + #else +@@ -559,11 +562,11 @@ + buf[len + 1] = TS0710_BASIC_FLAG; + + if ((COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX basic_write: (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)\n"); + + #ifndef USB_FOR_MUX +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX basic_write: tapisrv might be down!!! (serial_for_mux_driver == 0) || (serial_for_mux_tty == 0)\n"); + TS0710_SIG2APLOGD(); + #endif +@@ -577,7 +580,7 @@ + res = COMM_FOR_MUX_DRIVER->write(COMM_FOR_MUX_TTY, buf, len + 2); + + if (res != len + 2) { +- TS0710_PRINTK("MUX basic_write: Write Error!\n"); ++ TS0710_DEBUG("MUX basic_write: Write Error!\n"); + return -1; + } + +@@ -601,7 +604,7 @@ + TS0710_DEBUG("crc_check: CRC check OK\n"); + return 0; + } else { +- TS0710_PRINTK("MUX crc_check: CRC check failed\n"); ++ TS0710_DEBUG("MUX crc_check: CRC check failed\n"); + return 1; + } + } +@@ -1266,7 +1269,7 @@ + break; + + case FCON: /*Flow control on command */ +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX Received Flow control(all channels) on command\n"); + if (mcc_short_pkt->h.type.cr == MCC_CMD) { + ts0710->dlci[0].state = CONNECTED; +@@ -1276,7 +1279,7 @@ + break; + + case FCOFF: /*Flow control off command */ +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX Received Flow control(all channels) off command\n"); + if (mcc_short_pkt->h.type.cr == MCC_CMD) { + for (j = 0; j < TS0710_MAX_CHN; j++) { +@@ -1823,7 +1826,7 @@ + TS0710_DEBUG("UIH on channel %d\n", dlci); + + if (uih_len > ts0710->dlci[dlci].mtu) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX Error: DLCI:%d, uih_len:%d is bigger than mtu:%d, discard data!\n", + dlci, uih_len, ts0710->dlci[dlci].mtu); + break; +@@ -1844,7 +1847,7 @@ + dlci, tty_idx); + TS0710_DEBUGSTR(uih_data_start, uih_len); + if (!(iscmdtty[tty_idx])) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX Error: %s: Wrong CMDTAG on DLCI:%d, /dev/mux%d\n", + __FUNCTION__, dlci, tty_idx); + } +@@ -1856,7 +1859,7 @@ + ("NON-CMDTAG on DLCI:%d, /dev/mux%d\n", + dlci, tty_idx); + if (iscmdtty[tty_idx]) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX Error: %s: Wrong NON-CMDTAG on DLCI:%d, /dev/mux%d\n", + __FUNCTION__, dlci, tty_idx); + } +@@ -1864,13 +1867,14 @@ + } + tty = mux_table[tty_idx]; + if ((!mux_tty[tty_idx]) || (!tty)) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX: No application waiting for, discard it! /dev/mux%d\n", + tty_idx); ++ TS0710_DEBUG("MUX: mux_tty[%d] = %d, tty is at %i", tty_idx, mux_tty[tty_idx], tty); + } else { /* Begin processing received data */ + if ((!mux_recv_info_flags[tty_idx]) + || (!mux_recv_info[tty_idx])) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX Error: No mux_recv_info, discard it! /dev/mux%d\n", + tty_idx); + break; +@@ -1878,7 +1882,7 @@ + + recv_info = mux_recv_info[tty_idx]; + if (recv_info->total > 8192) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX : discard data for tty_idx:%d, recv_info->total > 8192 \n", + tty_idx); + break; +@@ -1949,7 +1953,7 @@ + get_mux_recv_packet + (uih_len); + if (!recv_packet) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX %s: no memory\n", + __FUNCTION__); + break; +@@ -1980,7 +1984,7 @@ + } else { /* recv_info->total == 0 */ + if (uih_len > + TS0710MUX_RECV_BUF_SIZE) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX Error: tty_idx:%d, uih_len == %d is too big\n", + tty_idx, uih_len); + uih_len = +@@ -2120,12 +2124,12 @@ + if (ts0710->dlci[dlci].state == DISCONNECTED) { + break; + } else if (signal_pending(current)) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI %d Send DISC got signal!\n", + dlci); + break; + } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI %d Send DISC timeout!\n", dlci); + continue; + } +@@ -2158,7 +2162,7 @@ + return 0; + } else if (ts0710->dlci[0].state == CONNECTING) { + /* Reentry */ +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI: 0, reentry to open DLCI 0, pid: %d, %s !\n", + current->pid, current->comm); + try = 11; +@@ -2179,13 +2183,13 @@ + DISCONNECTED) { + break; + } else if (signal_pending(current)) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI:%d Wait for connecting got signal!\n", + dlci); + retval = -EAGAIN; + break; + } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI:%d Wait for connecting timeout!\n", + dlci); + continue; +@@ -2199,7 +2203,7 @@ + } + } else if ((ts0710->dlci[0].state != DISCONNECTED) + && (ts0710->dlci[0].state != REJECTED)) { +- TS0710_PRINTK("MUX DLCI:%d state is invalid!\n", dlci); ++ TS0710_DEBUG("MUX DLCI:%d state is invalid!\n", dlci); + return retval; + } else { + ts0710->initiator = 1; +@@ -2218,19 +2222,19 @@ + retval = 0; + break; + } else if (ts0710->dlci[0].state == REJECTED) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI:%d Send SABM got rejected!\n", + dlci); + retval = -EREJECTED; + break; + } else if (signal_pending(current)) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI:%d Send SABM got signal!\n", + dlci); + retval = -EAGAIN; + break; + } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI:%d Send SABM timeout!\n", + dlci); + continue; +@@ -2271,13 +2275,13 @@ + DISCONNECTED) { + break; + } else if (signal_pending(current)) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI:%d Wait for connecting got signal!\n", + dlci); + retval = -EAGAIN; + break; + } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI:%d Wait for connecting timeout!\n", + dlci); + continue; +@@ -2296,7 +2300,7 @@ + } + } else if ((ts0710->dlci[dlci].state != DISCONNECTED) + && (ts0710->dlci[dlci].state != REJECTED)) { +- TS0710_PRINTK("MUX DLCI:%d state is invalid!\n", dlci); ++ TS0710_DEBUG("MUX DLCI:%d state is invalid!\n", dlci); + return retval; + } else { + ts0710->dlci[dlci].state = NEGOTIATING; +@@ -2313,13 +2317,13 @@ + if (ts0710->dlci[dlci].state == CONNECTING) { + break; + } else if (signal_pending(current)) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI:%d Send pn_msg got signal!\n", + dlci); + retval = -EAGAIN; + break; + } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI:%d Send pn_msg timeout!\n", + dlci); + continue; +@@ -2344,20 +2348,20 @@ + break; + } else if (ts0710->dlci[dlci].state == + REJECTED) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI:%d Send SABM got rejected!\n", + dlci); + retval = -EREJECTED; + break; + } else if (signal_pending(current)) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI:%d Send SABM got signal!\n", + dlci); + retval = -EAGAIN; + break; + } else if ((jiffies - t) >= + TS0710MUX_TIME_OUT) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX DLCI:%d Send SABM timeout!\n", + dlci); + continue; +@@ -2468,7 +2472,7 @@ + schedule_work(&send_tqueue); + #else + if (!tq_serial_for_mux) { +- TS0710_PRINTK("MUX Error: %s: tq_serial_for_mux == 0\n", ++ TS0710_DEBUG("MUX Error: %s: tq_serial_for_mux == 0\n", + __FUNCTION__); + return; + } +@@ -2508,7 +2512,7 @@ + if ((mux_tty[cmdtty] == 0) && (mux_tty[datatty] == 0)) { + if (dlci == 1) { + ts0710_close_channel(0); +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX mux_close: tapisrv might be down!!! Close DLCI 1\n"); + TS0710_SIG2APLOGD(); + } +@@ -2673,12 +2677,12 @@ + UNUSED_PARAM(tty); + + if ((COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX %s: (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)\n", + __FUNCTION__); + + #ifndef USB_FOR_MUX +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX %s: tapisrv might be down!!! (serial_for_mux_driver == 0) || (serial_for_mux_tty == 0)\n", + __FUNCTION__); + TS0710_SIG2APLOGD(); +@@ -2724,14 +2728,14 @@ + } else if (ts0710->dlci[dlci].state == CONNECTED) { + + if (!(mux_send_info_flags[line])) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX Error: mux_write: mux_send_info_flags[%d] == 0\n", + line); + return -ENODEV; + } + send_info = mux_send_info[line]; + if (!send_info) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX Error: mux_write: mux_send_info[%d] == 0\n", + line); + return -ENODEV; +@@ -2800,7 +2804,7 @@ + } + return c; + } else { +- TS0710_PRINTK("MUX mux_write: DLCI %d not connected\n", dlci); ++ TS0710_DEBUG("MUX mux_write: DLCI %d not connected\n", dlci); + return -EDISCONNECTED; + } + } +@@ -2940,7 +2944,7 @@ + return; + } + +- TS0710_PRINTK("MUX %s: line is:%d\n", __FUNCTION__, line); ++ TS0710_DEBUG("MUX %s: line is:%d\n", __FUNCTION__, line); + + if ((mux_send_info_flags[line]) + && (mux_send_info[line]) +@@ -2960,10 +2964,10 @@ + + /* + if( (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0) ) { +- TS0710_PRINTK("MUX %s: (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)\n", __FUNCTION__); ++ TS0710_DEBUG("MUX %s: (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)\n", __FUNCTION__); + + #ifndef USB_FOR_MUX +- TS0710_PRINTK("MUX %s: tapisrv might be down!!! (serial_for_mux_driver == 0) || (serial_for_mux_tty == 0)\n", __FUNCTION__); ++ TS0710_DEBUG("MUX %s: tapisrv might be down!!! (serial_for_mux_driver == 0) || (serial_for_mux_tty == 0)\n", __FUNCTION__); + TS0710_SIG2APLOGD(); + #endif + +@@ -2989,9 +2993,9 @@ + if ((COMM_FOR_MUX_DRIVER == NULL) || (COMM_FOR_MUX_TTY == NULL)) { + + #ifdef USB_FOR_MUX +- TS0710_PRINTK("MUX: please install and open IPC-USB first\n"); ++ TS0710_DEBUG("MUX: please install and open IPC-USB first\n"); + #else +- TS0710_PRINTK("MUX: please install and open ttyS0 first\n"); ++ TS0710_DEBUG("MUX: please install and open ttyS0 first\n"); + #endif + + goto out; +@@ -3016,7 +3020,7 @@ + /* if( dlci == 1 ) { */ + /* Open server channel 0 first */ + if ((retval = ts0710_open_channel(0)) != 0) { +- TS0710_PRINTK("MUX: Can't connect server channel 0!\n"); ++ TS0710_DEBUG("MUX: Can't connect server channel 0!\n"); + ts0710_init(); + + mux_tty[line]--; +@@ -3073,7 +3077,7 @@ + datatty = dlci2tty[dlci].datatty; + if ((mux_tty[cmdtty] > 0) || (mux_tty[datatty] > 0)) { + if ((retval = ts0710_open_channel(dlci)) != 0) { +- TS0710_PRINTK("MUX: Can't connected channel %d!\n", ++ TS0710_DEBUG("MUX: Can't connected channel %d!\n", + dlci); + ts0710_reset_dlci(dlci); + +@@ -3096,6 +3100,7 @@ + retval = 0; + #endif + out: ++ TS0710_DEBUG("returning %d for open of /dev/mux%d (mux_tty[%d] = %d", retval, line, line, mux_tty[line]); + return retval; + } + +@@ -3178,12 +3183,12 @@ + + while (1) { + tbuf_free = TS0710MUX_MAX_BUF_SIZE - (tbuf_ptr - tbuf); +- TS0710_PRINTK("Reading max %i bytes from ts0710_mux_usb inbuf.\n", tbuf_free); ++ TS0710_DEBUG("Reading max %i bytes from ts0710_mux_usb inbuf.\n", tbuf_free); + tbuf_read = get_from_inbuf_list(tbuf_ptr, tbuf_free); + if (tbuf_read == 0) { + break; + } else { +- TS0710_PRINTK("Read %i bytes.\n", tbuf_read); ++ TS0710_DEBUG("Read %i bytes.\n", tbuf_read); + }; + tbuf_ptr += tbuf_read; + }; +@@ -3192,7 +3197,7 @@ + + // Should be impossible? + //if (count > (TS0710MUX_MAX_BUF_SIZE - (tbuf_ptr - tbuf))) { +- // TS0710_PRINTK ++ // TS0710_DEBUG + // ("MUX receive_worker: !!!!! Exceed buffer boundary !!!!!\n"); + // count = (TS0710MUX_MAX_BUF_SIZE - (tbuf_ptr - tbuf)); + //} +@@ -3264,7 +3269,7 @@ + TS0710_LOGSTR_FRAME(0, start_flag, + (tbuf_ptr - + start_flag)); +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX Error: %s: frame length:%d is bigger than Max total frame size:%d\n", + /*__FUNCTION__, framelen, TS0710MUX_MAX_TOTAL_FRAME_SIZE);*/ + __FUNCTION__, framelen, (TS0710MUX_MAX_TOTAL_FRAME_SIZE + SEQ_FIELD_SIZE)); /*For BP UART problem */ +@@ -3389,7 +3394,7 @@ + *(uih_data_start + + uih_len) = + 0; +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX bp log: %s\n", + uih_data_start); + } +@@ -3415,7 +3420,7 @@ + TS0710_LOGSTR_FRAME(0, start_flag, + framelen); + TS0710_DEBUGHEX(start_flag, framelen); +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX: Lost synchronization!\n"); + search = start_flag + 1; + } +@@ -3476,7 +3481,7 @@ + recv_info2 = recv_info->next; + + if (!(recv_info->total)) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX Error: %s: Should not get here, recv_info->total == 0 \n", + __FUNCTION__); + continue; +@@ -3486,7 +3491,7 @@ + dlci = tty2dlci[tty_idx]; + tty = mux_table[tty_idx]; + if ((!mux_tty[tty_idx]) || (!tty)) { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX: No application waiting for, free recv_info! tty_idx:%d\n", + tty_idx); + mux_recv_info_flags[tty_idx] = 0; +@@ -3560,7 +3565,7 @@ + recv_info->total -= recv_packet->length; + free_mux_recv_packet(recv_packet); + } else { +- TS0710_PRINTK ++ TS0710_DEBUG + ("MUX Error: %s: Should not get here, recv_info->total is:%u \n", + __FUNCTION__, recv_info->total); + } +@@ -3760,7 +3765,7 @@ + int ret; + + if (idx > TS0710MUX_COUNT_MAX_IDX) { +- TS0710_PRINTK("MUX get_count: invalid idx: %d!\n", idx); ++ TS0710_DEBUG("MUX get_count: invalid idx: %d!\n", idx); + return -1; + } + +@@ -3774,11 +3779,11 @@ + static int set_count(__u8 idx, int count) + { + if (idx > TS0710MUX_COUNT_MAX_IDX) { +- TS0710_PRINTK("MUX set_count: invalid idx: %d!\n", idx); ++ TS0710_DEBUG("MUX set_count: invalid idx: %d!\n", idx); + return -1; + } + if (count < 0) { +- TS0710_PRINTK("MUX set_count: invalid count: %d!\n", count); ++ TS0710_DEBUG("MUX set_count: invalid count: %d!\n", count); + return -1; + } + +@@ -3792,11 +3797,11 @@ + static int add_count(__u8 idx, int count) + { + if (idx > TS0710MUX_COUNT_MAX_IDX) { +- TS0710_PRINTK("MUX add_count: invalid idx: %d!\n", idx); ++ TS0710_DEBUG("MUX add_count: invalid idx: %d!\n", idx); + return -1; + } + if (count <= 0) { +- TS0710_PRINTK("MUX add_count: invalid count: %d!\n", count); ++ TS0710_DEBUG("MUX add_count: invalid count: %d!\n", count); + return -1; + } + +Index: linux-2.6.20.7/drivers/char/ts0710_mux_usb.c +=================================================================== +--- linux-2.6.20.7.orig/drivers/char/ts0710_mux_usb.c 2007-04-22 12:26:47.000000000 +0200 ++++ linux-2.6.20.7/drivers/char/ts0710_mux_usb.c 2007-04-22 12:26:47.000000000 +0200 +@@ -72,7 +72,8 @@ + #define IPC_USB_PROBE_NOT_READY 4 + #define DBG_MAX_BUF_SIZE 1024 + #define ICL_EVENT_INTERVAL (HZ) +-#undef BVD_DEBUG ++ ++#define BVD_DEBUG + + #define IS_EP_BULK(ep) ((ep).bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0) + #define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) diff --git a/packages/linux/linux-ezx-2.6.20.7/usb_add_epalloc-r3.patch b/packages/linux/linux-ezx-2.6.20.7/usb_add_epalloc-r3.patch new file mode 100644 index 0000000000..fc9daf5297 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/usb_add_epalloc-r3.patch @@ -0,0 +1,282 @@ +Index: linux-2.6.20.7/drivers/usb/gadget/epautoconf.c +=================================================================== +--- linux-2.6.20.7.orig/drivers/usb/gadget/epautoconf.c 2007-04-21 11:24:21.000000000 -0300 ++++ linux-2.6.20.7/drivers/usb/gadget/epautoconf.c 2007-04-21 11:27:53.000000000 -0300 +@@ -228,14 +228,19 @@ + * + * On failure, this returns a null endpoint descriptor. + */ +-struct usb_ep * __devinit usb_ep_autoconfig ( ++struct usb_ep * 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. +Index: linux-2.6.20.7/drivers/usb/gadget/ether.c +=================================================================== +--- linux-2.6.20.7.orig/drivers/usb/gadget/ether.c 2007-04-21 11:27:52.000000000 -0300 ++++ linux-2.6.20.7/drivers/usb/gadget/ether.c 2007-04-21 11:27:53.000000000 -0300 +@@ -2219,7 +2219,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; + +@@ -2318,7 +2319,26 @@ + + /* 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; ++ ep_config[1].interface = rndis_data_intf.bInterfaceNumber; ++ 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, +@@ -2328,7 +2348,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 */ +@@ -2338,7 +2363,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) { +Index: linux-2.6.20.7/drivers/usb/gadget/file_storage.c +=================================================================== +--- linux-2.6.20.7.orig/drivers/usb/gadget/file_storage.c 2007-04-21 11:24:21.000000000 -0300 ++++ linux-2.6.20.7/drivers/usb/gadget/file_storage.c 2007-04-21 11:27:53.000000000 -0300 +@@ -3850,6 +3850,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); +@@ -3920,21 +3921,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 +Index: linux-2.6.20.7/drivers/usb/gadget/serial.c +=================================================================== +--- linux-2.6.20.7.orig/drivers/usb/gadget/serial.c 2007-04-21 11:24:21.000000000 -0300 ++++ linux-2.6.20.7/drivers/usb/gadget/serial.c 2007-04-21 11:27:53.000000000 -0300 +@@ -1357,6 +1357,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; +@@ -1377,22 +1378,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; +Index: linux-2.6.20.7/drivers/usb/gadget/zero.c +=================================================================== +--- linux-2.6.20.7.orig/drivers/usb/gadget/zero.c 2007-04-21 11:24:21.000000000 -0300 ++++ linux-2.6.20.7/drivers/usb/gadget/zero.c 2007-04-21 11:27:53.000000000 -0300 +@@ -1144,6 +1144,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. +@@ -1156,7 +1157,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", +@@ -1166,7 +1175,7 @@ + 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; +Index: linux-2.6.20.7/include/linux/usb_gadget.h +=================================================================== +--- linux-2.6.20.7.orig/include/linux/usb_gadget.h 2007-04-21 11:24:21.000000000 -0300 ++++ linux-2.6.20.7/include/linux/usb_gadget.h 2007-04-21 11:27:53.000000000 -0300 +@@ -445,10 +445,28 @@ + + 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); +@@ -872,7 +890,10 @@ + /* utility wrapping a simple endpoint selection policy */ + + extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, +- struct usb_endpoint_descriptor *) __devinit; ++ struct usb_endpoint_descriptor *, ++ struct usb_endpoint_config *, ++ int numconfigs ++); + + extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit; + diff --git a/packages/linux/linux-ezx-2.6.20.7/usb_pxa27x_udc-r3.patch b/packages/linux/linux-ezx-2.6.20.7/usb_pxa27x_udc-r3.patch new file mode 100644 index 0000000000..2e60d5b9ce --- /dev/null +++ b/packages/linux/linux-ezx-2.6.20.7/usb_pxa27x_udc-r3.patch @@ -0,0 +1,2868 @@ + arch/arm/mach-pxa/spitz.c | 27 + drivers/usb/gadget/Kconfig | 20 + drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/ether.c | 12 + drivers/usb/gadget/pxa27x_udc.c | 2412 ++++++++++++++++++++++++++++++++++++++++ + drivers/usb/gadget/pxa27x_udc.h | 298 ++++ + drivers/usb/gadget/pxa2xx_udc.h | 7 + 7 files changed, 2774 insertions(+), 3 deletions(-) + +Index: linux-2.6.20.7/arch/arm/mach-pxa/spitz.c +=================================================================== +--- linux-2.6.20.7.orig/arch/arm/mach-pxa/spitz.c 2007-04-21 12:21:53.000000000 -0300 ++++ linux-2.6.20.7/arch/arm/mach-pxa/spitz.c 2007-04-21 12:22:00.000000000 -0300 +@@ -348,6 +348,32 @@ + + + /* ++ * USB Client (Gadget/UDC) ++ */ ++static void spitz_udc_command(int cmd) ++{ ++ switch(cmd) { ++ case PXA2XX_UDC_CMD_CONNECT: ++ UP2OCR = UP2OCR_HXOE | UP2OCR_DMPUE | UP2OCR_DMPUBE; ++ break; ++ case PXA2XX_UDC_CMD_DISCONNECT: ++ //UP2OCR = UP2OCR_HXOE | UP2OCR_DMPUE | UP2OCR_DMPUBE; ++ break; ++ } ++} ++ ++static int spitz_udc_detect(void) ++{ ++ return 1; ++} ++ ++static struct pxa2xx_udc_mach_info spitz_udc_info __initdata = { ++ .udc_is_connected = spitz_udc_detect, ++ .udc_command = spitz_udc_command, ++}; ++ ++ ++/* + * USB Host (OHCI) + */ + static int spitz_ohci_init(struct device *dev) +@@ -498,6 +524,7 @@ + pxa_gpio_mode(SPITZ_GPIO_HSYNC | GPIO_IN); + + platform_add_devices(devices, ARRAY_SIZE(devices)); ++ pxa_set_udc_info(&spitz_udc_info); + pxa_set_mci_info(&spitz_mci_platform_data); + pxa_set_ohci_info(&spitz_ohci_platform_data); + pxa_set_ficp_info(&spitz_ficp_platform_data); +Index: linux-2.6.20.7/drivers/usb/gadget/Kconfig +=================================================================== +--- linux-2.6.20.7.orig/drivers/usb/gadget/Kconfig 2007-04-21 12:21:53.000000000 -0300 ++++ linux-2.6.20.7/drivers/usb/gadget/Kconfig 2007-04-21 12:22:00.000000000 -0300 +@@ -121,6 +121,26 @@ + default y if USB_ETH + default y if USB_G_SERIAL + ++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. ++ ++ It has 23 endpoints, as well as endpoint zero (for control ++ transfers). ++ ++ 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_GADGET_GOKU + boolean "Toshiba TC86C001 'Goku-S'" + depends on PCI +Index: linux-2.6.20.7/drivers/usb/gadget/Makefile +=================================================================== +--- linux-2.6.20.7.orig/drivers/usb/gadget/Makefile 2007-04-21 12:21:53.000000000 -0300 ++++ linux-2.6.20.7/drivers/usb/gadget/Makefile 2007-04-21 12:22:00.000000000 -0300 +@@ -4,6 +4,7 @@ + obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o + obj-$(CONFIG_USB_NET2280) += net2280.o + obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o ++obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o + obj-$(CONFIG_USB_GOKU) += goku_udc.o + obj-$(CONFIG_USB_OMAP) += omap_udc.o + obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o +Index: linux-2.6.20.7/drivers/usb/gadget/pxa27x_udc.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/drivers/usb/gadget/pxa27x_udc.c 2007-04-21 12:29:05.000000000 -0300 +@@ -0,0 +1,2412 @@ ++/* ++ * 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 <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/ioport.h> ++#include <linux/types.h> ++#include <linux/version.h> ++#include <linux/errno.h> ++#include <linux/platform_device.h> ++#include <linux/delay.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/timer.h> ++#include <linux/list.h> ++#include <linux/interrupt.h> ++#include <linux/proc_fs.h> ++#include <linux/mm.h> ++#include <linux/device.h> ++#include <linux/dma-mapping.h> ++ ++#include <asm/byteorder.h> ++#include <asm/dma.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/system.h> ++#include <asm/mach-types.h> ++#include <asm/unaligned.h> ++#include <asm/hardware.h> ++#include <asm/arch/pxa-regs.h> ++ ++#include <linux/usb_ch9.h> ++#include <linux/usb_gadget.h> ++ ++#include <asm/arch/udc.h> ++ ++/* ++ * 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 ++//#undef USE_DMA ++ ++#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 ++ ++#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. ++ */ ++ ++ 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 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(CKEN11_USB, 0); ++ ++ ep0_idle(dev); ++ dev->gadget.speed = USB_SPEED_UNKNOWN; ++ 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(CKEN11_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); ++ ++ DMSG("Connecting\n"); ++ /* RPFIXME */ ++ UP2OCR = UP2OCR_HXOE | UP2OCR_DPPUE | UP2OCR_DPPUBE; ++ //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, ++ }, ++}; ++ ++static int __init pxa27x_udc_probe(struct platform_device *_dev) ++{ ++ struct pxa27x_udc *dev = &memory; ++ int retval; ++ ++ /* other non-static parts of init */ ++ dev->dev = &_dev->dev; ++ dev->mach = _dev->dev.platform_data; ++ ++ /* RPFIXME */ ++ UP2OCR = UP2OCR_HXOE | UP2OCR_DPPUE | UP2OCR_DPPUBE; ++ ++ 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, ++ SA_INTERRUPT, 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 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; (i<UDC_EP_NUM); i++) { ++ if (dev->ep[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 = 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"); +Index: linux-2.6.20.7/drivers/usb/gadget/pxa27x_udc.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.20.7/drivers/usb/gadget/pxa27x_udc.h 2007-04-21 12:22:00.000000000 -0300 +@@ -0,0 +1,298 @@ ++/* ++ * linux/drivers/usb/gadget/pxa27x_udc.h ++ * Intel PXA27x on-chip full speed USB device controller ++ * ++ * Copyright (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, 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 <linux/types.h> ++ ++struct pxa27x_udc; ++ ++struct pxa27x_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; ++ ++ unsigned pxa_ep_num; ++ int dma; ++ unsigned fifo_size; ++ unsigned ep_type; ++ ++ unsigned stopped : 1; ++ unsigned dma_con : 1; ++ unsigned dir_in : 1; ++ unsigned assigned : 1; ++ ++ unsigned ep_num; ++ 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; ++}; ++ ++#define UDC_EP_NUM 24 ++ ++ ++struct pxa27x_udc { ++ struct usb_gadget gadget; ++ struct usb_gadget_driver *driver; ++ ++ enum ep0_state ep0state; ++ struct udc_stats stats; ++ unsigned got_irq : 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 ++}; ++ ++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].assigned) ++ 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)4) ++ ++#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 */ +Index: linux-2.6.20.7/drivers/usb/gadget/pxa2xx_udc.h +=================================================================== +--- linux-2.6.20.7.orig/drivers/usb/gadget/pxa2xx_udc.h 2007-04-21 12:21:53.000000000 -0300 ++++ linux-2.6.20.7/drivers/usb/gadget/pxa2xx_udc.h 2007-04-21 12:22:00.000000000 -0300 +@@ -259,7 +259,8 @@ + unsigned i; + + DMSG("%s %s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", +- is_usb_connected() ? "host " : "disconnected", ++ //is_usb_connected() ? "host " : "disconnected", ++ "host ", + state_name[dev->ep0state], + UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL); + dump_udccr("udccr"); +@@ -276,8 +277,8 @@ + } else + DMSG("ep0 driver '%s'\n", dev->driver->driver.name); + +- if (!is_usb_connected()) +- return; ++ //if (!is_usb_connected()) ++ // return; + + dump_udccs0 ("udccs0"); + DMSG("ep0 IN %lu/%lu, OUT %lu/%lu\n", +Index: linux-2.6.20.7/drivers/usb/gadget/ether.c +=================================================================== +--- linux-2.6.20.7.orig/drivers/usb/gadget/ether.c 2007-04-21 12:21:53.000000000 -0300 ++++ linux-2.6.20.7/drivers/usb/gadget/ether.c 2007-04-21 12:29:18.000000000 -0300 +@@ -1275,6 +1275,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; +@@ -1285,6 +1289,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); + } + diff --git a/packages/linux/linux-ezx_2.6.20.7.bb b/packages/linux/linux-ezx_2.6.20.7.bb new file mode 100644 index 0000000000..7336fee762 --- /dev/null +++ b/packages/linux/linux-ezx_2.6.20.7.bb @@ -0,0 +1,125 @@ +DESCRIPTION = "2.6 Linux Development Kernel for the Motorola GSM phones A780 and E680" +SECTION = "kernel" +AUTHOR = "Harald Welte and the OpenEZX Team <openezx-devel@lists.openezx.org>" +HOMEPAGE = "http://www.openezx.org" +LICENSE = "GPL" +DEPENDS += "quilt-native" +EZX = "ezx0" +PR = "${EZX}-r0" + +DEFAULT_PREFERENCE = "-1" + + +inherit kernel + +FILESDIR = "${@os.path.dirname(bb.data.getVar('FILE',d,1))}/linux-ezx" +RPSRC = "http://www.rpsys.net/openzaurus/patches/archive" + +############################################################## +# source and patches +# +SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-2.6.20.7.tar.bz2 \ + \ + file://ezx-core.patch;patch=1 \ + file://ezx-pcap.patch;patch=1 \ + file://ezx-mci.patch;patch=1 \ + file://usb_pxa27x_udc-r3.patch;patch=1 \ + file://usb_add_epalloc-r3.patch;patch=1 \ + file://ezx-emu.patch;patch=1 \ + file://ezx-fix-usb_pxa27x_udc-r3.patch;patch=1 \ + file://ezx-mtd-map.patch;patch=1 \ + file://ezx-serial-bug-workaround.patch;patch=1 \ + file://mux_cli.patch;patch=1 \ + file://mux-fix.patch;patch=1 \ + file://mux-fix-init-errorpath.patch;patch=1 \ + file://mux-remove-flipbuffers.patch;patch=1 \ + file://mux-remove-get_halted_bit.patch;patch=1 \ + file://mux-remove-usbh_finished_resume.patch;patch=1 \ + file://mux-fix-makefile.patch;patch=1 \ + file://mux-fix-tty-driver.patch;patch=1 \ + \ + file://logo_linux_clut224.ppm \ + file://defconfig-a780 \ + file://defconfig-e680 \ + " + +S = "${WORKDIR}/linux-2.6.20.7" + +############################################################## +# kernel image resides on a seperate flash partition (for now) +# +FILES_kernel-image = "" +ALLOW_EMPTY = "1" + +COMPATIBLE_HOST = "arm.*-linux" +COMPATIBLE_MACHINE = '(a780|e680)' + +CMDLINE_CON = "console=ttyS2,115200n8 console=tty1 noinitrd" +CMDLINE_ROOT = "root=/dev/mmcblk0p1 rootfstype=ext3 rootdelay=5" +# uncomment if you want to boot over NFS +#CMDLINE_ROOT = "root=/dev/nfs nfsroot=192.168.1.10:/export/opie-image rootdelay=5 3" +# uncomment to enable dyntick +#CMDLINE_OTHER = "dyntick=enable" +CMDLINE_DEBUG = '${@base_conditional("DISTRO_TYPE", "release", "quiet", "debug",d)}' +CMDLINE_IP = "ip=192.168.1.2:192.168.1.10:192.168.1.10:255.255.255.0:ezx:usb0:off" +CMDLINE = "${CMDLINE_CON} ${CMDLINE_ROOT} ${CMDLINE_IP} ${CMDLINE_ROTATE} ${CMDLINE_OTHER} ${CMDLINE_DEBUG} mem=32M@0xA0000000 mem=16M@0xAC000000" + +############################################################### +# module configs specific to this kernel +# +module_autoload_pxaficp_ir = "pxaficp_ir" +module_autoload_snd-pcm-oss = "snd-pcm-oss" + +do_configure() { + install -m 0644 ${WORKDIR}/logo_linux_clut224.ppm drivers/video/logo/logo_linux_clut224.ppm + + if [ ! -e ${WORKDIR}/defconfig-${MACHINE} ]; then + die "No default configuration for ${MACHINE} available." + fi + + echo "CONFIG_CMDLINE=\"${CMDLINE}\"" >> ${S}/.config + + if [ "${TARGET_OS}" == "linux-gnueabi" -o "${TARGET_OS}" == "linux-uclibcgnueabi" ]; then + echo "CONFIG_AEABI=y" >> ${S}/.config + echo "CONFIG_OABI_COMPAT=y" >> ${S}/.config + else + echo "# CONFIG_AEABI is not set" >> ${S}/.config + echo "# CONFIG_OABI_COMPAT is not set" >> ${S}/.config + fi + + sed -e '/CONFIG_AEABI/d' \ + -e '/CONFIG_OABI_COMPAT=/d' \ + -e '/CONFIG_CMDLINE=/d' \ + -e '/CONFIG_MTD_MTDRAM_SA1100=/d' \ + -e '/CONFIG_MTDRAM_TOTAL_SIZE=/d' \ + -e '/CONFIG_MTDRAM_ERASE_SIZE=/d' \ + -e '/CONFIG_MTDRAM_ABS_POS=/d' \ + '${WORKDIR}/defconfig-${MACHINE}' >>'${S}/.config' + + yes '' | oe_runmake oldconfig +} + +############################################################### +# check the kernel is below the 1024*1024 byte limit for the boot-over usb +# +do_compile_append() { + size=`ls -l arch/${ARCH}/boot/${KERNEL_IMAGETYPE} | awk '{ print $5}'` + if [ $size -ge 1294336 ]; then + rm arch/${ARCH}/boot/${KERNEL_IMAGETYPE} + echo "Size is $size" + echo "This kernel is too big for your EZX Phone. Please reduce the size of the kernel by making more of it modular." + fi +} + +############################################################### +# put into deploy directory +# +do_deploy() { + install -d ${DEPLOY_DIR_IMAGE} + install -m 0644 arch/${ARCH}/boot/${KERNEL_IMAGETYPE} ${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE}-${PV}-${MACHINE}-${DATETIME}.bin + tar -cvzf ${DEPLOY_DIR_IMAGE}/modules-${KERNEL_VERSION}-${MACHINE}.tgz -C ${D} lib +} + +do_deploy[dirs] = "${S}" + +addtask deploy before do_package after do_install |